C++ 策略模式(Strategy Pattern)
一、模式基础定义
策略模式属于行为型设计模式
核心思想:将不同业务算法独立封装成策略类 ,算法与业务主体解耦,运行时可自由替换算法,摒弃臃肿if-else判断,严格遵循开闭原则、单一职责原则。
适用核心场景:同一个行为存在多种实现方案,需要动态切换使用。
二、三大核心角色
| 角色 | 作用 | C++ 实现形式 |
|---|---|---|
| 抽象策略 Strategy | 定义统一算法接口,规范所有策略行为 | 抽象基类,包含纯虚函数 |
| 具体策略 ConcreteStrategy | 实现各自独立算法逻辑,互不干扰 | 派生类,重写虚接口 |
| 上下文 Context | 持有策略实例,对外统一调用入口,委托策略执行 | 聚合策略基类指针/智能指针 |
三、模式UML逻辑关系
- Context 聚合 Strategy 抽象类
- 多个 ConcreteStrategy 继承 Strategy
- 客户端操作 Context,动态注入不同具体策略
- 实际算法执行由具体策略类完成
四、经典面向对象实现(虚函数继承)
以排序算法切换为业务案例
cpp
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
// 抽象策略类
class SortStrategy
{
public:
virtual ~SortStrategy() = default;
virtual void sortData(std::vector<int>& arr) = 0;
};
// 具体策略1:冒泡排序
class BubbleSortStrategy : public SortStrategy
{
public:
void sortData(std::vector<int>& arr) override
{
int len = arr.size();
for (int i = 0; i < len - 1; ++i)
{
for (int j = 0; j < len - 1 - i; ++j)
{
if (arr[j] > arr[j + 1])
std::swap(arr[j], arr[j + 1]);
}
}
std::cout << "冒泡排序完成\n";
}
};
// 具体策略2:快速排序
class QuickSortStrategy : public SortStrategy
{
public:
void sortData(std::vector<int>& arr) override
{
std::sort(arr.begin(), arr.end());
std::cout << "快速排序完成\n";
}
};
// 具体策略3:插入排序
class InsertSortStrategy : public SortStrategy
{
public:
void sortData(std::vector<int>& arr) override
{
int len = arr.size();
for (int i = 1; i < len; ++i)
{
int temp = arr[i];
int j = i - 1;
while (j >= 0 && arr[j] > temp)
{
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = temp;
}
std::cout << "插入排序完成\n";
}
};
// 上下文环境类
class SortContext
{
private:
std::unique_ptr<SortStrategy> strategy;
public:
// 动态设置策略
void setStrategy(std::unique_ptr<SortStrategy> st)
{
strategy = std::move(st);
}
// 对外统一执行接口
void executeSort(std::vector<int>& arr)
{
if (strategy)
strategy->sortData(arr);
}
};
// 客户端调用
int main()
{
SortContext context;
std::vector<int> nums = {5, 2, 9, 1, 5, 6};
// 切换冒泡排序
context.setStrategy(std::make_unique<BubbleSortStrategy>());
context.executeSort(nums);
// 切换快速排序
context.setStrategy(std::make_unique<QuickSortStrategy>());
context.executeSort(nums);
// 切换插入排序
context.setStrategy(std::make_unique<InsertSortStrategy>());
context.executeSort(nums);
return 0;
}
五、现代C++轻量化实现(std::function 无继承)
无需定义抽象基类与派生类,适合无状态简单策略,代码极简,常用于折扣计算、权限校验、简单规则判断。
cpp
#include <iostream>
#include <functional>
#include <iomanip>
// 上下文类
class PriceContext
{
public:
using DiscountFunc = std::function<double(double)>;
explicit PriceContext(DiscountFunc func) : discountFunc(std::move(func)) {}
// 动态更换折扣策略
void changeStrategy(DiscountFunc func)
{
discountFunc = std::move(func);
}
// 计算最终价格
double getFinalPrice(double originPrice)
{
return discountFunc(originPrice);
}
private:
DiscountFunc discountFunc;
};
int main()
{
std::cout << std::fixed << std::setprecision(2);
// 原价策略
PriceContext ctx([](double p) { return p; });
std::cout << "原价:" << ctx.getFinalPrice(800) << std::endl;
// 9折优惠
ctx.changeStrategy([](double p) { return p * 0.9; });
std::cout << "9折价格:" << ctx.getFinalPrice(800) << std::endl;
// 满减策略
ctx.changeStrategy([](double p) { return p >= 500 ? p - 100 : p; });
std::cout << "满减价格:" << ctx.getFinalPrice(800) << std::endl;
return 0;
}
六、工程级扩展:策略工厂模式结合
项目中策略繁多时,通过工厂统一创建策略,字符串匹配获取对应算法,消除客户端new操作,便于配置文件读取策略。
cpp
#include <unordered_map>
#include <functional>
// 策略工厂
class StrategyFactory
{
public:
using StrategyCreator = std::function<std::unique_ptr<SortStrategy>()>;
static StrategyFactory& getInstance()
{
static StrategyFactory factory;
return factory;
}
// 注册策略
void registerStrategy(const std::string& name, StrategyCreator creator)
{
strategyMap[name] = std::move(creator);
}
// 获取策略实例
std::unique_ptr<SortStrategy> createStrategy(const std::string& name)
{
if (strategyMap.find(name) != strategyMap.end())
return strategyMap[name]();
return nullptr;
}
private:
StrategyFactory() = default;
std::unordered_map<std::string, StrategyCreator> strategyMap;
};
// 初始化注册策略
void initStrategy()
{
auto& factory = StrategyFactory::getInstance();
factory.registerStrategy("bubble", [](){return std::make_unique<BubbleSortStrategy>();});
factory.registerStrategy("quick", [](){return std::make_unique<QuickSortStrategy>();});
}
七、模式核心优缺点
优点
- 算法与业务解耦,算法独立维护修改
- 完美符合开闭原则,新增策略无需改动原有代码
- 消除大量
if/else分支代码,可读性大幅提升 - 运行时动态切换策略,灵活适配不同业务场景
- 策略类职责单一,单元测试方便
缺点
- 策略数量多会产生大量派生类,增加代码体量
- 客户端必须了解所有策略差异,才能合理选择
- 虚函数调用存在轻微运行开销,超高性能场景受限
- 策略之间无法共享局部数据
八、典型适用场景
- 同一功能存在多种算法实现:排序、加密、压缩、解析
- 商城多种优惠规则:折扣、满减、优惠券、积分抵扣
- 支付方式切换:微信、支付宝、银行卡支付
- 路由、权限、日志输出、数据导出格式切换
- 游戏技能、战斗模式、AI行为策略切换
九、易混淆设计模式对比
1. 策略模式 VS 状态模式
- 策略:客户端主动选择算法,算法间平等替换
- 状态:对象内部状态自动流转,被动切换行为
2. 策略模式 VS 模板方法
- 策略:组合关系,整体替换整套算法
- 模板方法:继承关系,仅重写算法局部步骤
3. 策略模式 VS 简单工厂
- 策略:侧重算法行为切换
- 工厂:侧重对象创建封装
十、C++ 开发最佳实践规范
- 优先使用
unique_ptr智能指针管理策略生命周期,杜绝内存泄漏 - 策略类设计为无状态,不保存成员变量数据,提升复用性
- 简单规则用
std::function+lambda,复杂算法使用继承策略 - 策略数量超过3个,建议搭配工厂统一管理创建
- 上下文设置默认策略,避免空指针调用崩溃
- 策略接口设计精简,减少参数耦合
- 禁止在策略类中调用业务上下文私有成员
十一、模式总结
策略模式本质封装变化点 ,把易变动的算法抽离为独立策略,固定不变的业务流程放在上下文。
C++ 中可根据项目复杂度,灵活选用继承虚函数 传统写法或函数对象轻量化写法,是日常开发替换条件分支、优化代码结构最常用的行为模式。