策略模式(Strategy):把算法抽出来,运行时可换
更新时间:2026-08-25。本文按"先看不用模式的困境 → 再用模式重构 → 类图对比分析"的结构,论述策略模式。可运行代码:demos/design-patterns/strategy。
一、问题场景:同一种行为有多种算法,且要可切换
压缩算法(gzip/zlib/lz4)、排序算法(快排/归并/计数)、计费策略(普通/VIP/团购)、路由选择(最短/最快/最稳)。算法的选择在运行时才定,且可能动态切换。
二、不使用模式:if/else 内嵌算法
cpp
double cost(Order& o, Type t) {
if (t == NORMAL) return o.price();
else if (t == VIP) return o.price() * 0.8;
else if (t == GROUP) return o.price() * 0.6;
else return 0; // 加新策略:改这里 + 全量回归
}| 缺陷 | 说明 |
|---|---|
| 违反 OCP | 加策略 = 加分支、改旧函数 |
| 违反 SRP | 上下文(订单计算)被所有策略塞满 |
| 算法不可复用 | 别的模块想用 VIP 折扣,只能复制分支 |
| 无法运行时切换 | 分支在编译期写死 |
不使用模式的类图

三、使用模式:算法独立成策略对象
策略模式定义策略接口,每个算法一个策略类;上下文(Context)持有策略引用,把算法委托给策略——运行时换策略 = 换一个对象。
cpp
// pricing_strategy.h
class PricingStrategy { // 策略接口
public:
virtual double price(const Order& o) const = 0;
virtual ~PricingStrategy() = default;
};
class NormalPricing : public PricingStrategy {
public:
double price(const Order& o) const override { return o.price(); }
};
class VipPricing : public PricingStrategy {
public:
double price(const Order& o) const override { return o.price() * 0.8; }
};
class GroupPricing : public PricingStrategy {
public:
double price(const Order& o) const override { return o.price() * 0.6; }
};
class Order { // 上下文
public:
explicit Order(double p) : price_(p) {}
void setStrategy(PricingStrategy& s) { strategy_ = &s; } // 运行时换策略
double total() const { return strategy_ ? strategy_->price(*this) : price_; }
double price() const { return price_; }
private:
double price_;
PricingStrategy* strategy_ = nullptr;
};
// 客户端:装配策略
NormalPricing np; VipPricing vp;
Order o(100); o.setStrategy(np); o.total(); // 100
o.setStrategy(vp); o.total(); // 80(运行时切换)使用模式的类图

四、类图对比与分析
| 维度 | 不使用(if/else) | 使用策略 |
|---|---|---|
| 加新算法 | 加分支、改旧函数 | 新增策略类 |
| 上下文职责 | 被所有算法塞满 | 只负责委托(SRP) |
| 算法复用 | 复制分支 | 策略类随处可装配 |
| 运行时切换 | 不可能 | setStrategy 即换 |
| 测试 | 全分支回归 | 每策略独立单测 |
分析结论:策略把"算法"变成一等公民对象,上下文从"装满算法的函数"瘦身为"委托者"。代价是多一组策略类 + 一次虚调用。本仓库性能视角:策略的虚调用在热点路径上可以测量(见 demos);若算法数量固定且极热,可用 std::function 或 switch+编译期分派替代。
五、适用边界
| 适用 | 不适用 |
|---|---|
| 同一行为多算法、运行时选择/切换 | 算法固定不变(策略是多余抽象) |
| 算法族持续扩展 | 极热路径对单次虚调用敏感(考虑内联/分支) |
| 消除巨型 if/else | 算法间无公共接口(强扭策略牵强) |
与状态模式的区别:策略换的是"算法"(对象不变、行为不同、由外部指定);状态换的是"状态"(对象按内部状态自驱动迁移)。策略是"喂给我算法",状态是"我自己会变"。
一句话总结
策略模式把算法抽成独立策略对象,上下文持有策略引用并运行时可换——加算法只加类、上下文不再臃肿、算法可复用;它是消除巨型 if/else 的首选,但算法固定或极热路径时不必引入。