1. 策略模式基础回顾
在C++中,策略模式是一种行为设计模式,它允许在运行时选择算法或行为。这种模式的核心思想是将算法封装在独立的类中,使得它们可以相互替换。策略模式让算法的变化独立于使用它的客户端。
1.1 基本结构解析
典型的策略模式包含三个关键组成部分:
- 策略接口(Strategy Interface):定义所有支持的算法或行为的公共接口
- 具体策略(Concrete Strategies):实现策略接口的具体算法类
- 上下文(Context):维护对策略对象的引用,并将工作委托给策略对象
// 策略接口 class SortingStrategy { public: virtual ~SortingStrategy() = default; virtual void sort(std::vector<int>& data) = 0; }; // 具体策略A:升序排序 class AscendingSort : public SortingStrategy { public: void sort(std::vector<int>& data) override { std::sort(data.begin(), data.end()); } }; // 具体策略B:降序排序 class DescendingSort : public SortingStrategy { public: void sort(std::vector<int>& data) override { std::sort(data.begin(), data.end(), std::greater<int>()); } }; // 上下文 class Sorter { std::unique_ptr<SortingStrategy> strategy; public: void setStrategy(std::unique_ptr<SortingStrategy> newStrategy) { strategy = std::move(newStrategy); } void executeSort(std::vector<int>& data) { if(strategy) { strategy->sort(data); } } };1.2 策略模式的优势
策略模式的主要优势在于:
- 开闭原则:可以在不修改现有代码的情况下引入新策略
- 消除条件语句:避免了大量的if-else或switch-case语句
- 运行时灵活性:算法可以在运行时动态切换
- 单一职责:每个策略类只负责一个算法或行为
提示:当发现类中有多个条件分支处理相似但不同的行为时,考虑使用策略模式重构。
2. 策略模式进阶实现
2.1 使用模板策略
在C++中,我们可以利用模板来实现编译时策略选择,这提供了更好的性能但牺牲了运行时的灵活性。
template<typename Strategy> class Context { Strategy strategy; public: void execute(const std::vector<int>& data) { strategy.process(data); } }; struct FastProcessing { void process(const std::vector<int>& data) { // 快速处理实现 } }; struct PreciseProcessing { void process(const std::vector<int>& data) { // 精确处理实现 } }; // 使用示例 Context<FastProcessing> fastContext; Context<PreciseProcessing> preciseContext;2.2 策略工厂模式
结合工厂模式可以更灵活地创建和管理策略对象:
class StrategyFactory { public: static std::unique_ptr<SortingStrategy> createStrategy(const std::string& type) { if(type == "ascending") { return std::make_unique<AscendingSort>(); } else if(type == "descending") { return std::make_unique<DescendingSort>(); } return nullptr; } };2.3 策略与多线程
在多线程环境中使用策略模式需要注意线程安全问题:
class ThreadSafeContext { std::mutex mtx; std::unique_ptr<SortingStrategy> strategy; public: void setStrategy(std::unique_ptr<SortingStrategy> newStrategy) { std::lock_guard<std::mutex> lock(mtx); strategy = std::move(newStrategy); } void executeSort(std::vector<int>& data) { std::lock_guard<std::mutex> lock(mtx); if(strategy) { strategy->sort(data); } } };3. 实际应用案例分析
3.1 游戏AI行为策略
在游戏开发中,策略模式常用于实现不同的AI行为:
class AIBehavior { public: virtual ~AIBehavior() = default; virtual void execute(GameCharacter& character) = 0; }; class AggressiveBehavior : public AIBehavior { public: void execute(GameCharacter& character) override { // 攻击最近的玩家 } }; class DefensiveBehavior : public AIBehavior { public: void execute(GameCharacter& character) override { // 寻找掩体并治疗 } }; class NeutralBehavior : public AIBehavior { public: void execute(GameCharacter& character) override { // 随机移动 } }; class GameCharacter { std::unique_ptr<AIBehavior> behavior; public: void setBehavior(std::unique_ptr<AIBehavior> newBehavior) { behavior = std::move(newBehavior); } void update() { if(behavior) { behavior->execute(*this); } } };3.2 数据解析策略
在处理不同格式的数据时,策略模式也非常有用:
class DataParser { public: virtual ~DataParser() = default; virtual Data parse(const std::string& input) = 0; }; class JSONParser : public DataParser { public: Data parse(const std::string& input) override { // JSON解析实现 } }; class XMLParser : public DataParser { public: Data parse(const std::string& input) override { // XML解析实现 } }; class CSVParser : public DataParser { public: Data parse(const std::string& input) override { // CSV解析实现 } }; class DataProcessor { std::unique_ptr<DataParser> parser; public: void setParser(std::unique_ptr<DataParser> newParser) { parser = std::move(newParser); } Data process(const std::string& input) { if(parser) { return parser->parse(input); } throw std::runtime_error("No parser set"); } };4. 性能优化与最佳实践
4.1 策略对象复用
频繁创建和销毁策略对象可能影响性能,可以考虑对象池模式:
class StrategyPool { std::unordered_map<std::string, std::shared_ptr<SortingStrategy>> pool; public: std::shared_ptr<SortingStrategy> getStrategy(const std::string& type) { auto it = pool.find(type); if(it != pool.end()) { return it->second; } std::shared_ptr<SortingStrategy> strategy; if(type == "ascending") { strategy = std::make_shared<AscendingSort>(); } else if(type == "descending") { strategy = std::make_shared<DescendingSort>(); } if(strategy) { pool[type] = strategy; } return strategy; } };4.2 策略与缓存结合
对于计算密集型策略,可以结合缓存机制:
class CachedStrategy : public SortingStrategy { std::unique_ptr<SortingStrategy> wrapped; mutable std::unordered_map<size_t, std::vector<int>> cache; public: explicit CachedStrategy(std::unique_ptr<SortingStrategy> strategy) : wrapped(std::move(strategy)) {} void sort(std::vector<int>& data) override { size_t key = std::hash<std::string>{}(std::string(data.begin(), data.end())); auto it = cache.find(key); if(it != cache.end()) { data = it->second; return; } wrapped->sort(data); cache[key] = data; } };4.3 策略模式与STL结合
现代C++中,我们可以使用函数对象和lambda表达式作为轻量级策略:
class GenericSorter { std::function<void(std::vector<int>&)> strategy; public: template<typename F> void setStrategy(F&& f) { strategy = std::forward<F>(f); } void execute(std::vector<int>& data) { if(strategy) { strategy(data); } } }; // 使用示例 GenericSorter sorter; sorter.setStrategy([](std::vector<int>& v) { std::sort(v.begin(), v.end()); });5. 常见问题与解决方案
5.1 策略选择逻辑复杂化
当策略选择逻辑变得复杂时,可以考虑:
- 使用策略工厂:将选择逻辑封装在工厂类中
- 引入规则引擎:对于非常复杂的选择逻辑
- 策略组合模式:允许策略的组合使用
class CompositeStrategy : public SortingStrategy { std::vector<std::unique_ptr<SortingStrategy>> strategies; public: void addStrategy(std::unique_ptr<SortingStrategy> strategy) { strategies.push_back(std::move(strategy)); } void sort(std::vector<int>& data) override { for(auto& strategy : strategies) { strategy->sort(data); } } };5.2 策略间状态共享
当策略需要共享状态时:
- 上下文传递:通过上下文对象共享状态
- 策略管理器:集中管理策略和共享状态
- 观察者模式:策略间通过事件通信
class SharedContext { std::unordered_map<std::string, std::any> state; public: template<typename T> void set(const std::string& key, const T& value) { state[key] = value; } template<typename T> T get(const std::string& key) const { return std::any_cast<T>(state.at(key)); } }; class ContextAwareStrategy : public SortingStrategy { std::shared_ptr<SharedContext> context; public: explicit ContextAwareStrategy(std::shared_ptr<SharedContext> ctx) : context(std::move(ctx)) {} void sort(std::vector<int>& data) override { // 可以使用context中的共享状态 } };5.3 策略模式与类型擦除
当需要处理不同类型的策略时,可以使用类型擦除技术:
class AnyStrategy { struct Concept { virtual ~Concept() = default; virtual void sort(std::vector<int>&) = 0; }; template<typename T> struct Model : Concept { T impl; explicit Model(T&& t) : impl(std::move(t)) {} void sort(std::vector<int>& data) override { impl.sort(data); } }; std::unique_ptr<Concept> impl; public: template<typename T> AnyStrategy(T&& t) : impl(new Model<T>(std::forward<T>(t))) {} void sort(std::vector<int>& data) { if(impl) impl->sort(data); } };6. 现代C++中的策略模式演进
6.1 使用std::variant实现策略模式
C++17引入的std::variant可以用来实现类型安全的策略模式:
using StrategyVariant = std::variant<AscendingSort, DescendingSort, RandomSort>; class VariantContext { StrategyVariant strategy; public: template<typename T> void setStrategy(T&& s) { strategy = std::forward<T>(s); } void execute(std::vector<int>& data) { std::visit([&data](auto&& s) { s.sort(data); }, strategy); } };6.2 策略模式与概念(Concepts)
C++20的概念(Concepts)可以更好地约束策略接口:
template<typename T> concept SortingStrategy = requires(T t, std::vector<int>& v) { { t.sort(v) } -> std::same_as<void>; }; template<SortingStrategy T> class ConceptContext { T strategy; public: ConceptContext(T&& s) : strategy(std::move(s)) {} void execute(std::vector<int>& data) { strategy.sort(data); } };6.3 策略模式的性能考量
在选择策略模式实现方式时,需要考虑以下性能因素:
- 虚函数开销:传统实现有虚函数调用开销
- 内存占用:策略对象的内存使用情况
- 缓存友好性:数据局部性对性能的影响
- 编译时优化:模板策略可以更好地优化
提示:在性能关键路径上,考虑使用模板策略或内联策略(lambda)来减少运行时开销。