1. 策略模式基础回顾与高级应用场景
在C++中,策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。这种模式让算法的变化独立于使用算法的客户端。我们先看一个经典实现示例:
cpp复制class SortStrategy {
public:
virtual void sort(vector<int>& data) = 0;
};
class QuickSort : public SortStrategy {
public:
void sort(vector<int>& data) override {
cout << "Using quick sort" << endl;
// 快速排序实现
}
};
class MergeSort : public SortStrategy {
public:
void sort(vector<int>& data) override {
cout << "Using merge sort" << endl;
// 归并排序实现
}
};
class Sorter {
private:
SortStrategy* strategy;
public:
Sorter(SortStrategy* strategy) : strategy(strategy) {}
void setStrategy(SortStrategy* strategy) {
this->strategy = strategy;
}
void executeSort(vector<int>& data) {
strategy->sort(data);
}
};
这个基础实现虽然展示了策略模式的核心思想,但在实际工程中往往需要更高级的应用技巧。以下是几个典型的高级应用场景:
- 动态策略切换:在运行时根据系统状态或配置动态切换策略
- 策略组合:将多个策略组合使用,形成更复杂的算法
- 策略工厂:结合工厂模式创建策略对象
- 模板策略:使用C++模板实现编译期策略选择
- 策略缓存:对策略计算结果进行缓存优化
提示:在性能敏感场景中,策略对象的创建和销毁开销需要特别注意。可以考虑使用对象池技术优化。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 现代C++中的策略模式实现技巧
2.1 使用std::function实现策略模式
C++11引入的std::function和lambda表达式为策略模式提供了更灵活的实现方式:
cpp复制class Sorter {
public:
using SortStrategy = std::function<void(vector<int>&)>;
void setStrategy(SortStrategy strategy) {
this->strategy = strategy;
}
void executeSort(vector<int>& data) {
strategy(data);
}
private:
SortStrategy strategy;
};
// 使用示例
Sorter sorter;
sorter.setStrategy([](vector<int>& data) {
cout << "Lambda sort strategy" << endl;
// 排序实现
});
这种实现方式的优势在于:
- 无需定义策略接口类
- 可以直接使用lambda表达式
- 更轻量级的策略对象
- 更好的内联优化机会
2.2 基于模板的策略模式
模板元编程可以提供编译期策略选择,完全消除运行时开销:
cpp复制template<typename Strategy>
class Sorter {
public:
void executeSort(vector<int>& data) {
Strategy::sort(data);
}
};
struct QuickSortPolicy {
static void sort(vector<int>& data) {
cout << "Template quick sort" << endl;
// 实现
}
};
// 使用示例
Sorter<QuickSortPolicy> sorter;
sorter.executeSort(data);
这种方式的优缺点比较:
| 优点 | 缺点 |
|---|---|
| 零运行时开销 | 编译期确定策略 |
| 更好的编译器优化 | 无法动态切换策略 |
| 类型安全 | 代码膨胀风险 |
2.3 策略模式与多线程安全
在多线程环境中使用策略模式需要特别注意:
- 策略对象的线程安全性:确保策略实现是线程安全的
- 策略切换的原子性:使用std::atomic或锁保护策略指针
- 避免策略执行中的竞态条件
一个线程安全的策略模式实现示例:
cpp复制class ThreadSafeSorter {
public:
void setStrategy(std::shared_ptr<SortStrategy> strategy) {
std::lock_guard<std::mutex> lock(mutex);
this->strategy = strategy;
}
void executeSort(vector<int>& data) {
std::shared_ptr<SortStrategy> local_strategy;
{
std::lock_guard<std::mutex> lock(mutex);
local_strategy = strategy;
}
local_strategy->sort(data);
}
private:
std::shared_ptr<SortStrategy> strategy;
std::mutex mutex;
};
3. 策略模式在复杂系统中的应用实践
3.1 游戏AI中的行为策略
在游戏开发中,策略模式常用于实现NPC的AI行为。例如,一个敌人可能有不同的攻击策略:
cpp复制class AttackStrategy {
public:
virtual void execute(Enemy& enemy, Player& player) = 0;
};
class MeleeAttack : public AttackStrategy {
void execute(Enemy& enemy, Player& player) override {
if(distance(enemy, player) < 5.0f) {
enemy.attack(player);
}
}
};
class RangedAttack : public AttackStrategy {
void execute(Enemy& enemy, Player& player) override {
if(distance(enemy, player) < 15.0f) {
enemy.shoot(player);
}
}
};
class EnemyAI {
private:
std::unique_ptr<AttackStrategy> strategy;
public:
void setStrategy(std::unique_ptr<AttackStrategy> newStrategy) {
strategy = std::move(newStrategy);
}
void update(Enemy& enemy, Player& player) {
strategy->execute(enemy, player);
}
};
这种设计允许:
- 动态调整敌人行为难度
- 混合使用多种策略
- 易于添加新行为类型
3.2 金融交易系统中的定价策略
在金融系统中,不同的产品可能需要不同的定价策略:
cpp复制class PricingStrategy {
public:
virtual double calculatePrice(const Trade& trade) = 0;
};
class FixedSpreadPricing : public PricingStrategy {
double calculatePrice(const Trade& trade) override {
return trade.marketPrice() + spread;
}
private:
double spread = 0.001;
};
class VolumeBasedPricing : public PricingStrategy {
double calculatePrice(const Trade& trade) override {
return trade.marketPrice() * (1.0 - trade.volume() * 0.0001);
}
};
class PricingEngine {
private:
std::map<ProductType, std::unique_ptr<PricingStrategy>> strategies;
public:
void setStrategy(ProductType type, std::unique_ptr<PricingStrategy> strategy) {
strategies[type] = std::move(strategy);
}
double priceTrade(const Trade& trade) {
auto it = strategies.find(trade.productType());
if(it != strategies.end()) {
return it->second->calculatePrice(trade);
}
throw std::runtime_error("No pricing strategy for product type");
}
};
3.3 网络协议处理中的解析策略
处理不同网络协议时,策略模式可以优雅地处理协议差异:
cpp复制class ProtocolHandler {
public:
virtual void handleRequest(const Request& req, Response& resp) = 0;
};
class HttpHandler : public ProtocolHandler {
void handleRequest(const Request& req, Response& resp) override {
// HTTP协议处理逻辑
}
};
class WebSocketHandler : public ProtocolHandler {
void handleRequest(const Request& req, Response& resp) override {
// WebSocket协议处理逻辑
}
};
class ProtocolDispatcher {
private:
std::unordered_map<std::string, std::unique_ptr<ProtocolHandler>> handlers;
public:
void registerHandler(const std::string& protocol, std::unique_ptr<ProtocolHandler> handler) {
handlers[protocol] = std::move(handler);
}
void dispatch(const Request& req, Response& resp) {
auto it = handlers.find(req.protocol());
if(it != handlers.end()) {
it->second->handleRequest(req, resp);
} else {
throw ProtocolNotSupported(req.protocol());
}
}
};
4. 策略模式性能优化与设计考量
4.1 策略对象生命周期管理
策略模式中策略对象的生命周期管理是一个重要考量点。常见的管理方式包括:
-
独占所有权:使用std::unique_ptr
cpp复制class Processor { private: std::unique_ptr<ProcessingStrategy> strategy; public: void setStrategy(std::unique_ptr<ProcessingStrategy> newStrategy) { strategy = std::move(newStrategy); } }; -
共享所有权:使用std::shared_ptr
cpp复制class Processor { private: std::shared_ptr<ProcessingStrategy> strategy; public: void setStrategy(std::shared_ptr<ProcessingStrategy> newStrategy) { strategy = newStrategy; } }; -
外部管理:使用原始指针(不推荐)
cpp复制class Processor { private: ProcessingStrategy* strategy = nullptr; public: void setStrategy(ProcessingStrategy* newStrategy) { strategy = newStrategy; } };
选择依据:
| 管理方式 | 适用场景 | 注意事项 |
|---|---|---|
| unique_ptr | 策略不共享且频繁更换 | 确保旧策略不再被使用 |
| shared_ptr | 策略可能被多个对象共享 | 注意循环引用问题 |
| 原始指针 | 性能极度敏感场景 | 必须确保策略对象生命周期 |
4.2 策略模式与缓存优化
对于计算密集型策略,可以考虑引入缓存机制:
cpp复制class CachedStrategy : public SortStrategy {
public:
CachedStrategy(std::unique_ptr<SortStrategy> realStrategy)
: realStrategy(std::move(realStrategy)) {}
void sort(vector<int>& data) override {
auto key = calculateCacheKey(data);
if(cache.find(key) != cache.end()) {
data = cache[key];
return;
}
realStrategy->sort(data);
cache[key] = data;
}
private:
std::unique_ptr<SortStrategy> realStrategy;
std::unordered_map<size_t, vector<int>> cache;
size_t calculateCacheKey(const vector<int>& data) {
// 简化的缓存键计算
return data.size();
}
};
4.3 策略模式与SIMD优化
在现代CPU架构下,可以利用SIMD指令优化策略实现:
cpp复制class SIMDSortStrategy : public SortStrategy {
public:
void sort(vector<int>& data) override {
#ifdef __AVX2__
// 使用AVX2指令集实现
avx2_sort(data.data(), data.size());
#else
// 回退到普通实现
std::sort(data.begin(), data.end());
#endif
}
};
这种实现可以根据CPU能力自动选择最优策略。
5. 策略模式与其他设计模式的结合
5.1 策略模式与工厂模式结合
策略工厂可以集中管理策略对象的创建:
cpp复制class StrategyFactory {
public:
static std::unique_ptr<SortStrategy> create(const std::string& name) {
if(name == "quick") return std::make_unique<QuickSort>();
if(name == "merge") return std::make_unique<MergeSort>();
if(name == "heap") return std::make_unique<HeapSort>();
throw std::invalid_argument("Unknown strategy");
}
};
// 使用示例
auto strategy = StrategyFactory::create("quick");
sorter.setStrategy(std::move(strategy));
5.2 策略模式与装饰器模式结合
装饰器模式可以为策略添加额外功能:
cpp复制class LoggingStrategy : public SortStrategy {
public:
LoggingStrategy(std::unique_ptr<SortStrategy> wrapped)
: wrapped(std::move(wrapped)) {}
void sort(vector<int>& data) override {
auto start = std::chrono::high_resolution_clock::now();
wrapped->sort(data);
auto end = std::chrono::high_resolution_clock::now();
std::cout << "Sort took "
<< std::chrono::duration_cast<std::chrono::microseconds>(end-start).count()
<< "μs" << std::endl;
}
private:
std::unique_ptr<SortStrategy> wrapped;
};
5.3 策略模式与观察者模式结合
策略执行结果可以被观察:
cpp复制class ObservableStrategy : public SortStrategy {
public:
void addObserver(std::function<void(const vector<int>&)> observer) {
observers.push_back(observer);
}
void sort(vector<int>& data) override {
// 实际排序逻辑
notifyObservers(data);
}
private:
std::vector<std::function<void(const vector<int>&)>> observers;
void notifyObservers(const vector<int>& data) {
for(auto& observer : observers) {
observer(data);
}
}
};
6. 策略模式的最佳实践与反模式
6.1 最佳实践
-
策略接口设计原则
- 保持策略接口精简
- 避免策略接口过于庞大
- 策略方法应该具有明确的单一职责
-
策略命名规范
- 使用
XxxStrategy作为策略类名后缀 - 使用动词短语命名策略方法,如
execute(),calculate()
- 使用
-
策略文档要求
- 明确说明每个策略的适用场景
- 记录策略的前置条件和后置条件
- 注明策略的时间/空间复杂度
6.2 常见反模式
-
策略膨胀:策略接口包含太多方法
cpp复制// 反模式示例 class BadStrategy { public: virtual void step1() = 0; virtual void step2() = 0; virtual void step3() = 0; // ...太多方法 }; -
策略耦合:策略之间相互依赖或了解
cpp复制// 反模式示例 class StrategyA : public Strategy { public: void execute() override { // 不应该知道其他策略的存在 if(condition) StrategyB().execute(); } }; -
上下文膨胀:上下文类包含太多与策略无关的状态
6.3 策略模式的测试策略
针对策略模式的测试应该考虑:
- 单元测试每个策略:验证每个策略实现的正确性
- 测试策略切换:验证上下文能正确切换不同策略
- 性能基准测试:比较不同策略的性能特征
- 异常场景测试:测试策略失败时的处理
示例测试用例:
cpp复制TEST(SorterTest, StrategySwitch) {
vector<int> data = {3,1,2};
Sorter sorter(std::make_unique<QuickSort>());
sorter.executeSort(data);
ASSERT_EQ(data, vector<int>{1,2,3});
sorter.setStrategy(std::make_unique<MergeSort>());
data = {3,1,2};
sorter.executeSort(data);
ASSERT_EQ(data, vector<int>{1,2,3});
}
7. C++20/23新特性对策略模式的影响
7.1 概念(Concepts)约束策略类型
C++20的概念可以更好地约束策略类型:
cpp复制template<typename T>
concept SortStrategy = requires(T s, vector<int> v) {
{ s.sort(v) } -> std::same_as<void>;
};
template<SortStrategy S>
class Sorter {
public:
void executeSort(vector<int>& data) {
S::sort(data);
}
};
7.2 使用协程实现异步策略
C++20协程可以实现异步策略:
cpp复制class AsyncStrategy {
public:
std::future<void> asyncSort(vector<int>& data) {
co_await std::async(std::launch::async, [&]{
// 异步排序实现
std::sort(data.begin(), data.end());
});
}
};
7.3 使用span优化策略接口
C++20的span可以优化策略接口:
cpp复制class SortStrategy {
public:
virtual void sort(std::span<int> data) = 0;
};
这种接口更灵活,可以处理数组、vector等各种连续容器。
8. 策略模式在实际项目中的调试技巧
8.1 策略追踪日志
添加策略执行追踪:
cpp复制class TracedStrategy : public SortStrategy {
public:
void sort(vector<int>& data) override {
cout << "Strategy invoked with data size: " << data.size() << endl;
realStrategy->sort(data);
cout << "Strategy completed" << endl;
}
TracedStrategy(std::unique_ptr<SortStrategy> realStrategy)
: realStrategy(std::move(realStrategy)) {}
private:
std::unique_ptr<SortStrategy> realStrategy;
};
8.2 策略性能剖析
使用性能分析工具测量策略执行时间:
cpp复制class ProfiledStrategy : public SortStrategy {
public:
void sort(vector<int>& data) override {
auto start = std::chrono::high_resolution_clock::now();
realStrategy->sort(data);
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end-start);
stats.record(duration.count());
}
void printStats() const {
cout << "Avg: " << stats.average() << "μs, "
<< "Max: " << stats.max() << "μs, "
<< "Min: " << stats.min() << "μs" << endl;
}
private:
std::unique_ptr<SortStrategy> realStrategy;
Statistics stats;
};
8.3 策略可视化调试
对于图形相关策略,可以添加可视化调试支持:
cpp复制class VisualSortStrategy : public SortStrategy {
public:
void sort(vector<int>& data) override {
visualize(data, "Initial state");
// 排序步骤1
step1(data);
visualize(data, "After step 1");
// 排序步骤2
step2(data);
visualize(data, "After step 2");
}
virtual void step1(vector<int>& data) = 0;
virtual void step2(vector<int>& data) = 0;
private:
void visualize(const vector<int>& data, const string& title) {
// 实现数据可视化,可以是控制台输出或图形界面
cout << title << ": ";
for(int n : data) cout << n << " ";
cout << endl;
}
};
在实际项目中,我发现策略模式最常出现的问题是策略对象生命周期管理不当。一个实用的调试技巧是在策略基类中添加构造/析构日志,确保策略对象在预期的时间被创建和销毁:
cpp复制class LoggedStrategy {
public:
LoggedStrategy() { cout << "Strategy created" << endl; }
virtual ~LoggedStrategy() { cout << "Strategy destroyed" << endl; }
};
