1. 策略模式基础概念解析
策略模式(Strategy Pattern)是GoF设计模式中行为型模式的经典代表,它定义了算法家族并分别封装起来,让它们之间可以互相替换。这种模式的核心在于将算法的使用与实现分离,使得算法可以独立于使用它的客户端变化。
在C++中实现策略模式通常包含三个关键角色:
- 环境类(Context):持有一个策略类的引用,最终给客户端调用
- 抽象策略类(Strategy):定义所有支持的算法的公共接口
- 具体策略类(ConcreteStrategy):实现了抽象策略定义的接口
提示:策略模式特别适合处理同一问题存在多种解决方案的场景,比如排序算法选择、支付方式切换等业务场景。
2. C++策略模式实现详解
2.1 基础实现框架
以下是策略模式在C++中的典型实现框架:
// 抽象策略类 class Strategy { public: virtual ~Strategy() = default; virtual void execute() const = 0; }; // 具体策略A class ConcreteStrategyA : public Strategy { public: void execute() const override { std::cout << "Executing Strategy A\n"; } }; // 具体策略B class ConcreteStrategyB : public Strategy { public: void execute() const override { std::cout << "Executing Strategy B\n"; } }; // 环境类 class Context { private: std::unique_ptr<Strategy> strategy_; public: explicit Context(std::unique_ptr<Strategy> strategy) : strategy_(std::move(strategy)) {} void setStrategy(std::unique_ptr<Strategy> strategy) { strategy_ = std::move(strategy); } void executeStrategy() const { strategy_->execute(); } };2.2 现代C++实现优化
现代C++(C++11及以上)提供了更多工具来优化策略模式的实现:
- 使用
std::function替代继承体系
class Context { private: std::function<void()> strategy_; public: explicit Context(std::function<void()> strategy) : strategy_(std::move(strategy)) {} void setStrategy(std::function<void()> strategy) { strategy_ = std::move(strategy); } void executeStrategy() const { strategy_(); } };- 结合lambda表达式使用
Context ctx([](){ std::cout << "Lambda strategy\n"; }); ctx.executeStrategy();3. 策略模式实战应用案例
3.1 排序算法选择器
假设我们需要实现一个排序工具,支持多种排序算法动态切换:
// 排序策略接口 class SortStrategy { public: virtual ~SortStrategy() = default; virtual void sort(std::vector<int>& data) const = 0; }; // 具体排序策略 class QuickSort : public SortStrategy { public: void sort(std::vector<int>& data) const override { std::cout << "Quick sorting...\n"; // 实际快速排序实现 } }; class MergeSort : public SortStrategy { public: void sort(std::vector<int>& data) const override { std::cout << "Merge sorting...\n"; // 实际归并排序实现 } }; // 排序上下文 class Sorter { private: std::unique_ptr<SortStrategy> strategy_; public: explicit Sorter(std::unique_ptr<SortStrategy> strategy) : strategy_(std::move(strategy)) {} void setStrategy(std::unique_ptr<SortStrategy> strategy) { strategy_ = std::move(strategy); } void executeSort(std::vector<int>& data) { strategy_->sort(data); } };3.2 电商支付系统设计
电商平台通常需要支持多种支付方式,策略模式非常适合这种场景:
// 支付策略接口 class PaymentStrategy { public: virtual ~PaymentStrategy() = default; virtual void pay(double amount) const = 0; }; // 具体支付策略 class CreditCardPayment : public PaymentStrategy { public: void pay(double amount) const override { std::cout << "Paying " << amount << " via Credit Card\n"; } }; class PayPalPayment : public PaymentStrategy { public: void pay(double amount) const override { std::cout << "Paying " << amount << " via PayPal\n"; } }; // 支付上下文 class PaymentProcessor { private: std::unique_ptr<PaymentStrategy> strategy_; public: explicit PaymentProcessor(std::unique_ptr<PaymentStrategy> strategy) : strategy_(std::move(strategy)) {} void setStrategy(std::unique_ptr<PaymentStrategy> strategy) { strategy_ = std::move(strategy); } void executePayment(double amount) { strategy_->pay(amount); } };4. 策略模式的高级应用技巧
4.1 策略对象创建优化
频繁创建策略对象可能带来性能开销,可以考虑以下优化方案:
- 策略对象复用
class StrategyFactory { private: std::unordered_map<std::string, std::shared_ptr<Strategy>> strategies_; public: StrategyFactory() { strategies_["A"] = std::make_shared<ConcreteStrategyA>(); strategies_["B"] = std::make_shared<ConcreteStrategyB>(); } std::shared_ptr<Strategy> getStrategy(const std::string& type) { return strategies_.at(type); } };- 使用轻量级策略对象
class StatelessStrategy { public: void operator()() const { std::cout << "Stateless strategy\n"; } }; Context ctx(StatelessStrategy{}); ctx.executeStrategy();4.2 策略组合模式
有时需要组合多个策略来实现复杂行为:
class CompositeStrategy : public Strategy { private: std::vector<std::shared_ptr<Strategy>> strategies_; public: void addStrategy(std::shared_ptr<Strategy> strategy) { strategies_.push_back(strategy); } void execute() const override { for (const auto& strategy : strategies_) { strategy->execute(); } } };5. 策略模式的最佳实践与陷阱规避
5.1 何时使用策略模式
策略模式特别适用于以下场景:
- 一个系统需要动态地在几种算法中选择一种
- 需要避免使用多重条件转移语句(if-else/switch-case)
- 算法的使用者不需要知道具体的算法实现细节
- 系统中有多个类只有算法行为不同
5.2 常见陷阱与解决方案
- 策略对象生命周期管理
注意:使用原始指针可能导致内存泄漏,建议使用智能指针(std::unique_ptr/std::shared_ptr)管理策略对象生命周期
策略接口膨胀 解决方案:将大接口拆分为多个小接口,遵循接口隔离原则
策略与上下文过度耦合 解决方案:通过依赖注入传递策略对象,避免上下文直接实例化具体策略
性能考虑 对于简单策略,考虑使用函数指针或std::function替代虚函数调用
5.3 测试策略模式
策略模式的一个显著优势是便于单元测试:
// 测试专用策略 class MockStrategy : public Strategy { public: MOCK_METHOD(void, execute, (), (const, override)); }; TEST(StrategyTest, ExecuteCalled) { MockStrategy mock; EXPECT_CALL(mock, execute()).Times(1); Context ctx(&mock); ctx.executeStrategy(); }6. 策略模式与其他模式的关系
6.1 与工厂模式的结合
策略模式常与工厂模式配合使用,实现策略对象的创建与管理分离:
class StrategyFactory { public: static std::unique_ptr<Strategy> create(const std::string& type) { if (type == "A") return std::make_unique<ConcreteStrategyA>(); if (type == "B") return std::make_unique<ConcreteStrategyB>(); throw std::invalid_argument("Unknown strategy type"); } }; // 使用示例 auto strategy = StrategyFactory::create("A"); Context ctx(std::move(strategy));6.2 与模板方法的区别
模板方法模式在父类中定义算法框架,而策略模式将整个算法封装为独立对象。前者通过继承实现行为变化,后者通过组合实现。
6.3 与命令模式的对比
命令模式将请求封装为对象,支持撤销、队列等操作;策略模式专注于算法的封装与替换。两者结构相似但意图不同。
7. C++20中的策略模式新写法
C++20引入的新特性可以进一步简化策略模式的实现:
- 使用概念(Concepts)约束策略类型
template <typename S> concept StrategyConcept = requires(S s) { { s.execute() } -> std::same_as<void>; }; template <StrategyConcept S> class Context { private: S strategy_; public: explicit Context(S strategy) : strategy_(strategy) {} void executeStrategy() const { strategy_.execute(); } };- 使用协程实现异步策略
class AsyncStrategy { public: std::future<void> execute() const { co_await std::suspend_always{}; std::cout << "Async strategy\n"; } };在实际项目中,我发现策略模式特别适合处理业务规则频繁变化的场景。通过将业务规则封装为策略对象,可以在不修改核心逻辑的情况下灵活应对需求变更。例如在金融系统中,不同客户可能需要应用不同的计费策略,使用策略模式可以优雅地实现这一需求。