C++设计模式:tur函数——让对象自我裁决的条件选择器

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函数体现了几个重要的编程思想:

  1. 数据驱动:逻辑围绕数据自身的属性展开
  2. 自我认知:对象能够判断自己是否满足条件
  3. 防御性编程:优雅地处理异常值
  4. 类型安全 :通过模板和std::function保证类型正确性

优缺点分析

优点

  • 代码自文档化:清晰地表达"让对象自我判断"的意图
  • 类型安全:编译期类型检查
  • 复用性强:判断逻辑可以作为参数传入
  • 组合灵活:可以链式调用

缺点

  • 性能开销std::function有轻微的类型擦除开销
  • 语法稍显繁琐 :需要显式创建std::function
  • 学习曲线:需要理解函数式编程思想

总结

tur函数虽然实现简单,但其"让对象自我裁决"的思想却很深刻。它不是简单的语法糖,而是一种让代码更符合"数据驱动"理念的设计模式。在实际开发中,这种模式特别适合处理配置系统、数据验证、参数检查等需要根据对象自身状态做决策的场景。

思考题

你能想到其他适合使用这种模式的应用场景吗?欢迎在评论区分享你的想法!

相关推荐
无级程序员2 小时前
k8s部署nacos 3.1.1服务,java.net.UnknownHostException问题终极解决方案
java·nacos·kubernetes
C++chaofan2 小时前
JUC 并发编程:不可变对象、享元模式与自定义连接池 学习笔记
java·享元模式·并发编程·连接池·juc·不可变对象
掘根2 小时前
【即时通讯系统】环境搭建5——httplib,websocketpp
c++
big_rabbit05022 小时前
[算法][力扣242]有效的字母异位词
java·前端·leetcode
小年糕是糕手2 小时前
【35天从0开始备战蓝桥杯 -- Day4】
数据结构·c++·算法·leetcode·蓝桥杯
xcLeigh2 小时前
复杂 SQL 过滤时机过晚?金仓基于代价的连接条件下推方案来了
java·数据库·sql语句·union·金仓·kingbasees
xiaoye-duck2 小时前
《算法题讲解指南:递归,搜索与回溯算法--递归》--1.汉诺塔,2.合并两个有序链表
数据结构·c++·算法
星轨zb2 小时前
非遗AI对话系统架构升级实战
java·人工智能·redis·后端·系统架构
iPadiPhone2 小时前
Spring Boot 核心注解全维度解析与面试复盘
java·spring boot·后端·spring·面试