C++设计模式:tur函数------让对象自我裁决的条件选择器
文章目录
引言
在C++编程中,我们经常需要根据条件来决定使用原值还是兜底值。传统的三元运算符或if语句虽然简单,但都是外部逻辑 在替对象做决定。今天要介绍的tur函数,采用了一种全新的思路:让对象根据自身属性,自己决定是否"够格"被使用。
什么是tur函数?
tur是一个模板函数,它接受三个参数:
- 第一个参数:需要判断的目标对象
- 第二个参数 :一个返回bool值的判断函数(固定为
std::function<bool(T&)>类型) - 第三个参数:兜底值(当判断失败时返回)
cpp
template<typename T, typename Fallback>
auto tur(T& value, std::function<bool(T&)> judge, Fallback fallback) {
if (judge(value)) {
return value; // 满足条件,返回自身
} else {
return fallback; // 不满足条件,返回兜底值
}
}
核心思想:自我裁决
传统条件判断(外部裁决)
cpp
// 外部逻辑决定值的命运
if (num > 50) {
result = num; // 使用原值
} else {
result = 0; // 使用兜底值
}
tur函数(自我裁决)
cpp
// 让对象根据自身属性做决定
int result = tur(num,
std::function<bool(int&)>([](int& n) { return n > 50; }),
0
);
// num自己判断是否大于50,决定返回自己还是0
关键区别:判断的标准来自于对象自身的状态,而不是外部写死的条件。
完整实现
cpp
#include <iostream>
#include <string>
#include <functional>
#include <type_traits>
// tur函数:让对象自我裁决
template<typename T, typename Fallback>
auto tur(T& value, std::function<bool(T&)> judge, Fallback fallback) {
if (judge(value)) {
return value;
} else {
return fallback;
}
}
// 辅助函数:简化std::function的创建
template<typename T, typename Func>
auto judge(Func&& func) {
return std::function<bool(T&)>(std::forward<Func>(func));
}
// 智能字符串转换(展示tur的实用场景)
template<typename T>
std::string to_str(T& t) {
// 准备兜底值
std::string fallback;
if constexpr (std::is_same_v<T, const char*> || std::is_same_v<T, char*>) {
fallback = std::string(t);
} else if constexpr (std::is_arithmetic_v<T>) {
fallback = std::to_string(t);
} else if constexpr (!std::is_same_v<T, std::string>) {
fallback = "[不支持的类型]";
}
// 让对象自己决定是否需要特殊处理
auto raw = tur(t,
std::function<bool(T&)>([](T&) -> bool {
return std::is_same_v<T, std::string>;
}),
fallback
);
// 统一返回std::string
if constexpr (std::is_same_v<decltype(raw), std::string> ||
std::is_same_v<decltype(raw), const std::string>) {
return raw;
} else if constexpr (std::is_same_v<decltype(raw), const char*> ||
std::is_same_v<decltype(raw), char*>) {
return std::string(raw);
} else if constexpr (std::is_arithmetic_v<std::remove_reference_t<decltype(raw)>>) {
return std::to_string(raw);
} else {
return "[未知类型]";
}
}
实际应用场景
场景1:配置系统(空值处理)
cpp
class Config {
std::string host;
std::string port;
int timeout;
public:
Config() : host(""), port(""), timeout(0) {}
void setHost(const std::string& h) { host = h; }
void setPort(const std::string& p) { port = p; }
void setTimeout(int t) { timeout = t; }
std::string getHost() { return host; }
std::string getPort() { return port; }
int getTimeout() { return timeout; }
};
void configureSystem() {
Config config;
config.setHost("localhost");
// port和timeout未设置
// 获取配置:如果已设置就用设置值,否则用默认值
auto host = tur(config.getHost(),
judge<std::string>([](std::string& s) { return !s.empty(); }),
std::string("127.0.0.1"));
auto port = tur(config.getPort(),
judge<std::string>([](std::string& s) { return !s.empty(); }),
std::string("8080"));
auto timeout = tur(config.getTimeout(),
judge<int>([](int& t) { return t > 0; }),
30);
std::cout << "连接 " << host << ":" << port
<< " 超时 " << timeout << "秒" << std::endl;
}
场景2:传感器数据验证
cpp
class SensorSystem {
// 模拟传感器读数
double readTemperature() {
// 有时返回错误码 -999.0
return rand() % 10 == 0 ? -999.0 : 20.0 + rand() % 30;
}
double readPressure() {
return rand() % 10 == 0 ? 0.0 : 1000.0 + rand() % 50;
}
public:
void monitor() {
double temp = readTemperature();
double pressure = readPressure();
// 让数据自我验证
auto validTemp = tur(temp,
judge<double>([](double& t) {
return t > -50 && t < 100; // 合理温度范围
}),
25.0); // 默认室温
auto validPressure = tur(pressure,
judge<double>([](double& p) {
return p > 900 && p < 1100; // 合理气压范围
}),
1013.25); // 标准大气压
std::cout << "温度: " << validTemp << "°C, "
<< "气压: " << validPressure << "hPa" << std::endl;
}
};
场景3:用户输入验证
cpp
class UserInput {
std::string username;
std::string email;
int age;
public:
UserInput() : username(""), email(""), age(0) {}
void setUsername(const std::string& name) { username = name; }
void setEmail(const std::string& mail) { email = mail; }
void setAge(int a) { age = a; }
std::string getUsername() { return username; }
std::string getEmail() { return email; }
int getAge() { return age; }
};
void processUser() {
UserInput input;
input.setUsername("john_doe");
input.setAge(25);
// email未设置
// 验证并处理用户输入
auto username = tur(input.getUsername(),
judge<std::string>([](std::string& s) {
return s.length() >= 3 && s.length() <= 20;
}),
std::string("guest"));
auto email = tur(input.getEmail(),
judge<std::string>([](std::string& s) {
return s.find('@') != std::string::npos;
}),
std::string("pending@email.com"));
auto age = tur(input.getAge(),
judge<int>([](int& a) {
return a >= 18 && a <= 120;
}),
18);
std::cout << "用户: " << username << ", "
<< "邮箱: " << email << ", "
<< "年龄: " << age << std::endl;
}
场景4:链式调用
cpp
class DataProcessor {
std::string data;
public:
DataProcessor(const std::string& d) : data(d) {}
DataProcessor& validate() {
data = tur(data,
judge<std::string>([](std::string& s) {
return !s.empty() && s.length() < 1000;
}),
std::string("[无效数据]"));
return *this;
}
DataProcessor& trim() {
if (!data.empty() && data != "[无效数据]") {
// 去除首尾空格
size_t start = data.find_first_not_of(" \t\n\r");
size_t end = data.find_last_not_of(" \t\n\r");
if (start != std::string::npos) {
data = data.substr(start, end - start + 1);
}
}
return *this;
}
std::string get() const { return data; }
};
void processData() {
std::string rawData = " Hello World ";
DataProcessor proc(rawData);
std::string result = proc.validate().trim().get();
std::cout << "处理结果: '" << result << "'" << std::endl;
}
完整测试程序
cpp
int main() {
std::cout << "=== tur函数测试 ===\n" << std::endl;
// 1. 数值测试
int score = 85;
int failScore = 45;
auto judge_pass = judge<int>([](int& s) { return s >= 60; });
std::cout << "成绩85: " << tur(score, judge_pass, 0) << std::endl;
std::cout << "成绩45: " << tur(failScore, judge_pass, 0) << std::endl;
// 2. 字符串测试
std::string name = "Alice";
std::string emptyName = "";
auto judge_name = judge<std::string>([](std::string& n) {
return !n.empty() && n.length() >= 2;
});
std::cout << "\n名字Alice: " << tur(name, judge_name, std::string("Unknown")) << std::endl;
std::cout << "空名字: " << tur(emptyName, judge_name, std::string("Unknown")) << std::endl;
// 3. 指针测试
int* validPtr = new int(42);
int* nullPtr = nullptr;
auto judge_ptr = judge<int*>([](int*& p) { return p != nullptr; });
std::cout << "\n有效指针: " << *tur(validPtr, judge_ptr, nullPtr) << std::endl;
std::cout << "空指针: " << (tur(nullPtr, judge_ptr, validPtr) == validPtr ? "使用备用" : "空") << std::endl;
delete validPtr;
// 4. 配置系统测试
std::cout << "\n=== 配置系统测试 ===" << std::endl;
configureSystem();
// 5. 传感器测试
std::cout << "\n=== 传感器监控 ===" << std::endl;
SensorSystem sensors;
for (int i = 0; i < 5; i++) {
sensors.monitor();
}
// 6. 用户输入测试
std::cout << "\n=== 用户处理 ===" << std::endl;
processUser();
// 7. 数据处理测试
std::cout << "\n=== 数据处理 ===" << std::endl;
processData();
// 8. to_str测试
std::cout << "\n=== to_str转换 ===" << std::endl;
std::string str = "Hello C++";
const char* cstr = "World";
int num = 2024;
double pi = 3.14159;
std::cout << "string: " << to_str(str) << std::endl;
std::cout << "cstring: " << to_str(cstr) << std::endl;
std::cout << "int: " << to_str(num) << std::endl;
std::cout << "double: " << to_str(pi) << std::endl;
return 0;
}
设计哲学
tur函数体现了几个重要的编程思想:
- 数据驱动:逻辑围绕数据自身的属性展开
- 自我认知:对象能够判断自己是否满足条件
- 防御性编程:优雅地处理异常值
- 类型安全 :通过模板和
std::function保证类型正确性
优缺点分析
优点
- 代码自文档化:清晰地表达"让对象自我判断"的意图
- 类型安全:编译期类型检查
- 复用性强:判断逻辑可以作为参数传入
- 组合灵活:可以链式调用
缺点
- 性能开销 :
std::function有轻微的类型擦除开销 - 语法稍显繁琐 :需要显式创建
std::function - 学习曲线:需要理解函数式编程思想
总结
tur函数虽然实现简单,但其"让对象自我裁决"的思想却很深刻。它不是简单的语法糖,而是一种让代码更符合"数据驱动"理念的设计模式。在实际开发中,这种模式特别适合处理配置系统、数据验证、参数检查等需要根据对象自身状态做决策的场景。
思考题
你能想到其他适合使用这种模式的应用场景吗?欢迎在评论区分享你的想法!