第一部分:模式基础详解
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 应用场景
典型场景:
- 多种支付方式:微信、支付宝、银行卡
- 数据压缩算法:ZIP、RAR、7Z
- 排序算法:快速排序、归并排序、冒泡排序
- 文件加密:AES、DES、RSA
- 出行方式:步行、公交、地铁、打车
- 促销活动:满减、打折、赠送礼品
判断标准:
- 需要在不同情况下使用不同的业务规则
- 避免使用大量的条件判断(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 最佳实践
- 配合工厂模式:使用工厂创建策略对象,进一步解耦
- 使用函数对象:C++中可以使用std::function代替策略接口
- 考虑线程安全:策略类通常设计为无状态的
- 合理使用模板:编译期策略可以使用模板实现
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 策略思维在生活中的映射
-
交通工具选择
- 上下文:你的出行
- 策略:步行、公交、地铁、打车、骑行
- 思维:路线固定,方式可变
-
烹饪方法
- 上下文:食材处理
- 策略:煎、炒、煮、炸、蒸
- 思维:食材固定,烹饪方式可互换
-
学习方式
- 上下文:知识获取
- 策略:阅读、听课、实践、讨论
- 思维:学习目标固定,方法可组合
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 思维升级:从模式到原则
策略模式体现的设计原则:
- 开闭原则:对扩展开放,对修改关闭
- 依赖倒置:依赖抽象,不依赖具体
- 接口隔离:策略接口精简专一
- 里氏替换:子类型必须能替换父类型
- 单一职责:算法与使用分离
第三部分:总结与思维升华
最终思维总结
策略模式的最高境界是形成策略性思维:
"遇到变化,先问:这个变化可以参数化吗?这个算法可以作为策略吗?"
这种思维让你:
- 从硬编码的奴隶变成配置的主人
- 从预测需求变成拥抱变化
- 从修改代码变成组装组件
- 从程序员思维升级为架构师思维
实践建议
- 入门阶段:先识别代码中的if-else/switch,尝试重构
- 进阶阶段:思考哪些算法可以独立变化,主动抽象
- 高级阶段:将策略思维应用到系统架构、业务流程设计
- 大师阶段:形成肌肉记忆,遇到问题自动浮现策略模式选项
记住:代码会腐朽,但策略思维永存。今天学的是策略模式,明天会的是如何用策略思维解决任何领域的问题。当你能在编写任何一行代码之前就想到"这里未来可能需要变化,我应该把它设计成可配置的策略"时,你就真正掌握了策略模式的精髓。