13.C++设计模式-策略模式

第一部分:模式基础详解

1.1 模式定义

策略模式(Strategy Pattern)定义了一系列算法,将每个算法封装起来,使它们可以互相替换。策略模式让算法的变化独立于使用算法的客户端。

1.2 模式结构

Context
-Strategy* strategy
+setStrategy(Strategy* s)
+executeStrategy()
<<interface>>
Strategy
+execute()
ConcreteStrategyA
+execute()
ConcreteStrategyB
+execute()

1.3 核心角色

  • Context(上下文):维护策略引用,负责调用策略
  • Strategy(策略接口):定义所有策略的公共接口
  • ConcreteStrategy(具体策略):实现具体算法

1.4 应用场景

典型场景:
  1. 多种支付方式:微信、支付宝、银行卡
  2. 数据压缩算法:ZIP、RAR、7Z
  3. 排序算法:快速排序、归并排序、冒泡排序
  4. 文件加密:AES、DES、RSA
  5. 出行方式:步行、公交、地铁、打车
  6. 促销活动:满减、打折、赠送礼品
判断标准:
  • 需要在不同情况下使用不同的业务规则
  • 避免使用大量的条件判断(if-else/switch)
  • 算法经常变化或扩展

1.5 C++代码示例

示例1:计算器(基础实现)
cpp 复制代码
#include <iostream>
#include <memory>

// 策略接口
class CalculationStrategy {
public:
    virtual ~CalculationStrategy() = default;
    virtual int calculate(int a, int b) const = 0;
};

// 具体策略:加法
class AddStrategy : public CalculationStrategy {
public:
    int calculate(int a, int b) const override {
        return a + b;
    }
};

// 具体策略:减法
class SubtractStrategy : public CalculationStrategy {
public:
    int calculate(int a, int b) const override {
        return a - b;
    }
};

// 具体策略:乘法
class MultiplyStrategy : public CalculationStrategy {
public:
    int calculate(int a, int b) const override {
        return a * b;
    }
};

// 上下文
class Calculator {
private:
    std::unique_ptr<CalculationStrategy> strategy;
    
public:
    void setStrategy(std::unique_ptr<CalculationStrategy> s) {
        strategy = std::move(s);
    }
    
    int executeStrategy(int a, int b) const {
        if (!strategy) {
            throw std::runtime_error("Strategy not set");
        }
        return strategy->calculate(a, b);
    }
};

// 使用示例
int main() {
    Calculator calc;
    
    // 使用加法
    calc.setStrategy(std::make_unique<AddStrategy>());
    std::cout << "10 + 5 = " << calc.executeStrategy(10, 5) << std::endl;
    
    // 使用减法
    calc.setStrategy(std::make_unique<SubtractStrategy>());
    std::cout << "10 - 5 = " << calc.executeStrategy(10, 5) << std::endl;
    
    // 使用乘法
    calc.setStrategy(std::make_unique<MultiplyStrategy>());
    std::cout << "10 * 5 = " << calc.executeStrategy(10, 5) << std::endl;
    
    return 0;
}
示例2:支付系统(实际应用)
cpp 复制代码
#include <iostream>
#include <string>
#include <memory>
#include <ctime>

// 支付结果
struct PaymentResult {
    bool success;
    std::string message;
    std::string transactionId;
};

// 策略接口
class PaymentStrategy {
public:
    virtual ~PaymentStrategy() = default;
    virtual PaymentResult pay(double amount) const = 0;
    virtual std::string getType() const = 0;
};

// 支付宝支付
class AlipayStrategy : public PaymentStrategy {
private:
    std::string account;
    std::string password;
    
public:
    AlipayStrategy(const std::string& acc, const std::string& pwd) 
        : account(acc), password(pwd) {}
    
    PaymentResult pay(double amount) const override {
        PaymentResult result;
        // 模拟支付宝支付逻辑
        if (account.find("@") != std::string::npos) {
            result.success = true;
            result.message = "支付宝支付成功";
            result.transactionId = "ALI" + std::to_string(time(nullptr));
            std::cout << "使用支付宝支付 " << amount << " 元" << std::endl;
        } else {
            result.success = false;
            result.message = "支付宝账号格式错误";
        }
        return result;
    }
    
    std::string getType() const override {
        return "Alipay";
    }
};

// 微信支付
class WeChatPayStrategy : public PaymentStrategy {
private:
    std::string openId;
    
public:
    WeChatPayStrategy(const std::string& id) : openId(id) {}
    
    PaymentResult pay(double amount) const override {
        PaymentResult result;
        if (openId.length() > 10) {
            result.success = true;
            result.message = "微信支付成功";
            result.transactionId = "WX" + std::to_string(time(nullptr));
            std::cout << "使用微信支付 " << amount << " 元" << std::endl;
        } else {
            result.success = false;
            result.message = "微信OpenID无效";
        }
        return result;
    }
    
    std::string getType() const override {
        return "WeChatPay";
    }
};

// 信用卡支付
class CreditCardStrategy : public PaymentStrategy {
private:
    std::string cardNumber;
    std::string cvv;
    std::string expiryDate;
    
public:
    CreditCardStrategy(const std::string& card, const std::string& cvv, 
                       const std::string& expiry)
        : cardNumber(card), cvv(cvv), expiryDate(expiry) {}
    
    PaymentResult pay(double amount) const override {
        PaymentResult result;
        if (cardNumber.length() == 16 && cvv.length() == 3) {
            result.success = true;
            result.message = "信用卡支付成功";
            result.transactionId = "CC" + std::to_string(time(nullptr));
            std::cout << "使用信用卡支付 " << amount << " 元" << std::endl;
        } else {
            result.success = false;
            result.message = "信用卡信息无效";
        }
        return result;
    }
    
    std::string getType() const override {
        return "CreditCard";
    }
};

// 订单上下文
class Order {
private:
    double amount;
    std::unique_ptr<PaymentStrategy> paymentStrategy;
    
public:
    Order(double amt) : amount(amt) {}
    
    void setPaymentStrategy(std::unique_ptr<PaymentStrategy> strategy) {
        paymentStrategy = std::move(strategy);
    }
    
    void checkout() {
        if (!paymentStrategy) {
            std::cout << "请先选择支付方式!" << std::endl;
            return;
        }
        
        std::cout << "\n订单金额:" << amount << " 元" << std::endl;
        std::cout << "支付方式:" << paymentStrategy->getType() << std::endl;
        
        PaymentResult result = paymentStrategy->pay(amount);
        
        if (result.success) {
            std::cout << "✓ " << result.message << std::endl;
            std::cout << "交易号:" << result.transactionId << std::endl;
        } else {
            std::cout << "✗ 支付失败:" << result.message << std::endl;
        }
    }
};

// 使用示例
int main() {
    // 创建订单
    Order order(299.99);
    
    // 使用支付宝支付
    order.setPaymentStrategy(std::make_unique<AlipayStrategy>(
        "user@example.com", "password123"));
    order.checkout();
    
    // 使用微信支付
    order.setPaymentStrategy(std::make_unique<WeChatPayStrategy>(
        "wxid_12345678901234567890"));
    order.checkout();
    
    // 使用信用卡支付
    order.setPaymentStrategy(std::make_unique<CreditCardStrategy>(
        "1234567890123456", "123", "12/25"));
    order.checkout();
    
    return 0;
}

1.6 策略模式流程图

客户端创建Context
客户端选择具体策略
将策略注入Context
调用Context执行方法
Context调用策略的execute方法
策略A执行
策略B执行
策略C执行
返回结果

1.7 优缺点

优点:
  • 开闭原则:增加新策略无需修改现有代码
  • 避免多重条件判断:消除if-else/switch语句
  • 提高复用性:策略可独立测试和复用
  • 运行时切换:可以在运行时动态改变行为
缺点:
  • 类数量增加:每个策略都需要一个类
  • 客户端需了解策略:客户端必须知道有哪些策略可用
  • 策略间无法共享数据:策略对象间是独立的

1.8 与其他模式对比

模式 目的 区别
策略模式 封装算法族 算法可互换
状态模式 根据状态改变行为 状态自动转换
命令模式 封装请求 支持撤销、队列等
工厂模式 创建对象 关注对象创建

1.9 最佳实践

  1. 配合工厂模式:使用工厂创建策略对象,进一步解耦
  2. 使用函数对象:C++中可以使用std::function代替策略接口
  3. 考虑线程安全:策略类通常设计为无状态的
  4. 合理使用模板:编译期策略可以使用模板实现
cpp 复制代码
// 使用std::function的简化版本
#include <functional>

class SimpleCalculator {
private:
    std::function<int(int,int)> strategy;
    
public:
    void setStrategy(std::function<int(int,int)> s) {
        strategy = s;
    }
    
    int execute(int a, int b) {
        return strategy(a, b);
    }
};

// 使用
SimpleCalculator calc;
calc.setStrategy([](int a, int b) { return a + b; });
calc.execute(10, 5); // 15

第二部分:深层思想思维

策略模式不仅仅是一种编码技巧,更是一种思维范式。让我从更高维度解析它的思想精髓。

2.1 核心哲学思想

组合优于继承

策略组合思维
主体对象
策略组件
策略组件
策略组件
传统继承思维
基类
子类1
子类2
子类3

思想转变

  • 不是:"我是什么"(继承)
  • 而是:"我有什么"(组合)
cpp 复制代码
// ❌ 继承思维:通过继承扩展行为
class Duck {
    virtual void quack() = 0;
    virtual void fly() = 0;
};

class MallardDuck : public Duck {
    void quack() override { /* 呱呱叫 */ }
    void fly() override { /* 飞 */ }
};

class RubberDuck : public Duck {
    void quack() override { /* 吱吱叫 */ }
    void fly() override { /* 不能飞 */ }  // 问题:覆盖了不需要的行为
};

// ✅ 组合思维:通过策略组装行为
class Duck {
    std::unique_ptr<QuackBehavior> quackBehavior;
    std::unique_ptr<FlyBehavior> flyBehavior;
    // 动态组装,灵活复用
};
关注点分离

策略模式体现了"算法与上下文分离"的设计哲学:
只关心接口
具体实现
具体实现
具体实现
需求变更
性能优化
合规调整
业务逻辑 Context
抽象策略
算法1
算法2
算法3
业务变化原因
技术升级原因
政策法规原因

关键洞察:不同部分的变化原因和频率不同,应该分开封装。

2.2 认知维度的思维转变

维度1:从"判断思维"到"映射思维"
cpp 复制代码
// ❌ 判断思维:遇到选择就想if-else
if (type == "A") {
    // 200行代码
} else if (type == "B") {
    // 200行代码
} else if (type == "C") {
    // 200行代码
}

// ✅ 映射思维:建立策略映射表
std::unordered_map<string, unique_ptr<Strategy>> strategies = {
    {"A", make_unique<StrategyA>()},
    {"B", make_unique<StrategyB>()},
    {"C", make_unique<StrategyC>()}
};
strategies[type]->execute();

思维模型:将决策树转换为查找表

维度2:从"硬编码"到"参数化"

参数化思维
定义
指定
替换策略
代码
行为接口
配置/注入
具体策略
修改
安全
硬编码思维
写死
改代码
代码
具体行为
修改
风险

维度3:从"垂直扩展"到"水平扩展"
cpp 复制代码
// 垂直扩展:增加新类型(修改现有类)
class Order {
    // 每增加支付方式,都要修改这个类
    void pay() {
        if (type == "alipay") { /* ... */ }
        else if (type == "wechat") { /* ... */ }
        else if (type == "paypal") { /* ... */ } // 新增
    }
};

// 水平扩展:增加新策略(不修改现有类)
class Order {
    void pay(PaymentStrategy* strategy) {
        strategy->pay(); // 无需修改,接受任何新策略
    }
};

2.3 策略思维在生活中的映射

  1. 交通工具选择

    • 上下文:你的出行
    • 策略:步行、公交、地铁、打车、骑行
    • 思维:路线固定,方式可变
  2. 烹饪方法

    • 上下文:食材处理
    • 策略:煎、炒、煮、炸、蒸
    • 思维:食材固定,烹饪方式可互换
  3. 学习方式

    • 上下文:知识获取
    • 策略:阅读、听课、实践、讨论
    • 思维:学习目标固定,方法可组合

2.4 高阶思维模式

思维1:"策略即配置"

将业务逻辑视为可配置的组件:

cpp 复制代码
// 通过配置化实现热插拔
class Application {
    std::vector<Strategy> strategies;
    
    void loadFromConfig(const string& configFile) {
        // 从配置文件动态加载策略
        // 无需重新编译,改变运行时行为
    }
};
思维2:"策略作为一等公民"

将策略提升到与数据同等重要的位置:

cpp 复制代码
// 策略可以:
// 1. 被存储
vector<Strategy> history;

// 2. 被传递
void process(Strategy s) { /* ... */ }

// 3. 被组合
class CompositeStrategy : public Strategy {
    vector<Strategy> strategies;
    void execute() override {
        for (auto& s : strategies) s->execute();
    }
};

// 4. 被动态创建
Strategy createStrategy(const string& name) { /* 工厂模式 */ }
思维3:"策略的量化与评估"
cpp 复制代码
// 为策略添加评估机制
class Strategy {
    virtual double cost() = 0;      // 成本
    virtual double quality() = 0;   // 质量
    virtual double time() = 0;      // 时间
};

// 运行时选择最优策略
Strategy* selectOptimal() {
    return find_if(strategies.begin(), strategies.end(),
        [](auto& s) { return s->quality() / s->cost() > threshold; });
}

2.5 与真实世界的类比

乐高积木思维

对比
传统雕塑思维 = 继承模式
单一整体

紧耦合基类
固定形态

难以修改
改变局部

修改子类
整体受影响

破坏继承链
乐高思维 = 策略模式
基础积木块

策略接口
标准化接口

可互换
任意组合

灵活组装
更换单个积木

替换具体策略
不影响整体结构

开闭原则

医生诊疗思维
  • 症状(问题)
  • 病人(上下文)
  • 治疗方案(策略)
  • 同病不同治(策略可替换)

2.6 反模式陷阱识别

陷阱1:过度策略化
cpp 复制代码
// ❌ 过度设计:只有一种实现也用策略
class AddStrategy {
    int execute(int a, int b) { return a + b; }
};

// ✅ 简单场景直接实现
int add(int a, int b) { return a + b; }
陷阱2:策略泄露
cpp 复制代码
// ❌ 上下文需要知道策略细节
class Context {
    void execute() {
        if (dynamic_cast<Alipay*>(strategy.get())) {
            // 特殊处理支付宝
        }
    }
};

// ✅ 策略完全封装
class Context {
    void execute() {
        strategy->pay();  // 完全不知道具体策略
    }
};

2.7 思维升级:从模式到原则

策略模式体现的设计原则:

  1. 开闭原则:对扩展开放,对修改关闭
  2. 依赖倒置:依赖抽象,不依赖具体
  3. 接口隔离:策略接口精简专一
  4. 里氏替换:子类型必须能替换父类型
  5. 单一职责:算法与使用分离

第三部分:总结与思维升华

最终思维总结

策略模式的最高境界是形成策略性思维

"遇到变化,先问:这个变化可以参数化吗?这个算法可以作为策略吗?"

这种思维让你:

  • 从硬编码的奴隶变成配置的主人
  • 从预测需求变成拥抱变化
  • 从修改代码变成组装组件
  • 从程序员思维升级为架构师思维

实践建议

  1. 入门阶段:先识别代码中的if-else/switch,尝试重构
  2. 进阶阶段:思考哪些算法可以独立变化,主动抽象
  3. 高级阶段:将策略思维应用到系统架构、业务流程设计
  4. 大师阶段:形成肌肉记忆,遇到问题自动浮现策略模式选项

记住:代码会腐朽,但策略思维永存。今天学的是策略模式,明天会的是如何用策略思维解决任何领域的问题。当你能在编写任何一行代码之前就想到"这里未来可能需要变化,我应该把它设计成可配置的策略"时,你就真正掌握了策略模式的精髓。

相关推荐
计算机安禾5 小时前
【c++面向对象编程】第36篇:析构函数应永远不抛出异常——原因与最佳实践
开发语言·c++
therese_100865 小时前
客户端架构:为什么、什么时候、怎么做
设计模式·安卓·鸿蒙
ゆづき5 小时前
假如编程语言们有外号
java·c语言·c++·python·学习·c#·生活
REDcker14 小时前
有限状态机与状态模式详解 FSM建模Java状态模式与C++表驱动模板实践
java·c++·状态模式
多加点辣也没关系15 小时前
设计模式-解释器模式
设计模式·解释器模式
basketball61615 小时前
C++ 构造函数完全指南:从入门到进阶
java·开发语言·c++
想唱rap16 小时前
IO多路转接之poll
服务器·开发语言·数据库·c++
落羽的落羽17 小时前
【算法札记】练习 | Week4
linux·服务器·数据结构·c++·人工智能·算法·动态规划
goodesocket17 小时前
芯片HAST测试:通电工作下如何精准模拟极端环境挑战?
c++