1. 策略模式基础回顾与核心价值
策略模式(Strategy Pattern)作为行为型设计模式的代表,在C++中常被用于实现算法的动态切换。其核心思想是将算法家族封装成独立的类,使它们可以相互替换。这种模式让算法的变化独立于使用算法的客户端。
在标准实现中,策略模式包含三个关键角色:
- Context(上下文):持有一个策略类的引用,通过接口与策略交互
- Strategy(抽象策略):定义所有支持的算法的公共接口
- ConcreteStrategy(具体策略):实现抽象策略定义的接口,提供具体算法
cpp复制// 抽象策略接口
class SortingStrategy {
public:
virtual void sort(vector<int>& data) = 0;
virtual ~SortingStrategy() = default;
};
// 具体策略A
class QuickSort : public SortingStrategy {
public:
void sort(vector<int>& data) override {
cout << "Using quick sort algorithm" << endl;
// 快速排序实现...
}
};
// 具体策略B
class MergeSort : public SortingStrategy {
public:
void sort(vector<int>& data) override {
cout << "Using merge sort algorithm" << endl;
// 归并排序实现...
}
};
// 上下文类
class SortContext {
private:
unique_ptr<SortingStrategy> strategy;
public:
void setStrategy(unique_ptr<SortingStrategy> newStrategy) {
strategy = move(newStrategy);
}
void executeSort(vector<int>& data) {
if(strategy) {
strategy->sort(data);
}
}
};
策略模式的核心价值在于:
- 开闭原则:无需修改上下文即可引入新策略
- 消除条件语句:替代大量的if-else或switch-case语句
- 算法复用:相同算法可在不同上下文中复用
- 运行时灵活性:算法选择延迟到运行时决定
提示:在C++中实现策略模式时,优先使用智能指针(如unique_ptr)管理策略对象生命周期,避免内存泄漏问题。
2. 高级应用场景:策略组合与复合策略
在实际工程中,单一策略往往难以满足复杂业务需求。通过策略的组合使用,可以构建更强大的灵活系统。
2.1 策略链模式
将多个策略按顺序链接执行,形成处理管道。每个策略完成特定处理后将结果传递给下一个策略。
cpp复制class ValidationStrategy {
public:
virtual bool validate(const string& input) = 0;
virtual ~ValidationStrategy() = default;
};
// 长度验证策略
class LengthValidation : public ValidationStrategy {
public:
bool validate(const string& input) override {
return input.length() >= 8;
}
};
// 数字包含策略
class DigitValidation : public ValidationStrategy {
public:
bool validate(const string& input) override {
return any_of(input.begin(), input.end(), ::isdigit);
}
};
// 策略链上下文
class ValidationPipeline {
private:
vector<unique_ptr<ValidationStrategy>> strategies;
public:
void addStrategy(unique_ptr<ValidationStrategy> strategy) {
strategies.push_back(move(strategy));
}
bool validateAll(const string& input) {
for(const auto& strategy : strategies) {
if(!strategy->validate(input)) return false;
}
return true;
}
};
2.2 复合策略模式
将多个策略组合成一个超级策略,内部协调各子策略的执行顺序和交互方式。
cpp复制class PricingStrategy {
public:
virtual double calculatePrice(double basePrice) = 0;
virtual ~PricingStrategy() = default;
};
// 折扣策略
class DiscountStrategy : public PricingStrategy {
private:
double discountRate;
public:
explicit DiscountStrategy(double rate) : discountRate(rate) {}
double calculatePrice(double basePrice) override {
return basePrice * (1 - discountRate);
}
};
// 税费策略
class TaxStrategy : public PricingStrategy {
private:
double taxRate;
public:
explicit TaxStrategy(double rate) : taxRate(rate) {}
double calculatePrice(double basePrice) override {
return basePrice * (1 + taxRate);
}
};
// 复合定价策略
class CompositePricingStrategy : public PricingStrategy {
private:
vector<unique_ptr<PricingStrategy>> strategies;
public:
void addStrategy(unique_ptr<PricingStrategy> strategy) {
strategies.push_back(move(strategy));
}
double calculatePrice(double basePrice) override {
double currentPrice = basePrice;
for(const auto& strategy : strategies) {
currentPrice = strategy->calculatePrice(currentPrice);
}
return currentPrice;
}
};
在实际项目中,我曾遇到一个电商价格计算需求,需要同时考虑会员折扣、促销活动、税费和运费。通过复合策略模式,我们将每个计算因素封装为独立策略,最终组合出完整的价格计算流程。这种设计使得后期新增优惠券、积分抵扣等功能时,只需添加新策略而无需修改现有代码。
3. 策略模式的性能优化技巧
虽然策略模式提供了优秀的扩展性,但在高性能场景下需要考虑额外的优化手段。
3.1 策略对象复用
频繁创建销毁策略对象会导致性能损耗,可通过对象池技术复用策略实例:
cpp复制class StrategyPool {
private:
unordered_map<size_t, vector<unique_ptr<SortingStrategy>>> pools;
public:
template<typename T>
T* acquire() {
size_t typeHash = typeid(T).hash_code();
if(pools[typeHash].empty()) {
pools[typeHash].push_back(make_unique<T>());
}
auto& pool = pools[typeHash];
auto ptr = pool.back().release();
pool.pop_back();
return dynamic_cast<T*>(ptr);
}
template<typename T>
void release(T* strategy) {
size_t typeHash = typeid(T).hash_code();
pools[typeHash].push_back(unique_ptr<T>(strategy));
}
};
3.2 编译时策略选择
对于在编译期即可确定的策略,可使用模板元编程实现零成本抽象:
cpp复制template<typename Strategy>
class SortedVector {
private:
vector<int> data;
Strategy sorter;
public:
void add(int value) { data.push_back(value); }
void sort() {
sorter.sort(data);
}
};
// 使用示例
SortedVector<QuickSort> sv;
sv.add(5); sv.add(2); sv.add(8);
sv.sort();
3.3 策略无状态化
当策略无需维护内部状态时,可简化为函数对象,大幅提升性能:
cpp复制using SortStrategy = function<void(vector<int>&)>;
class SortContext {
private:
SortStrategy strategy;
public:
void setStrategy(SortStrategy newStrategy) {
strategy = newStrategy;
}
void executeSort(vector<int>& data) {
if(strategy) strategy(data);
}
};
// 使用lambda表达式作为策略
SortContext ctx;
ctx.setStrategy([](vector<int>& data) {
sort(data.begin(), data.end());
});
在最近的一个高频交易系统开发中,我们通过将策略无状态化并结合std::function,使订单路由策略的执行时间从约200ns降低到50ns左右,满足了系统的低延迟要求。
4. 策略模式在大型项目中的架构实践
4.1 策略工厂与依赖注入
在复杂系统中,通常需要集中管理策略的创建过程。策略工厂模式结合依赖注入可以优雅地解决这个问题:
cpp复制class StrategyFactory {
public:
virtual unique_ptr<SortingStrategy> create(const string& config) = 0;
virtual ~StrategyFactory() = default;
};
class DefaultSortStrategyFactory : public StrategyFactory {
public:
unique_ptr<SortingStrategy> create(const string& config) override {
if(config == "fast") return make_unique<QuickSort>();
if(config == "stable") return make_unique<MergeSort>();
throw invalid_argument("Unknown strategy config");
}
};
class Application {
private:
unique_ptr<SortingStrategy> strategy;
public:
// 通过构造函数注入策略工厂
explicit Application(StrategyFactory& factory) {
strategy = factory.create("fast");
}
void processData(vector<int>& data) {
strategy->sort(data);
// 其他处理逻辑...
}
};
4.2 策略的配置化加载
将策略选择逻辑外置到配置文件中,实现真正的运行时动态配置:
json复制// strategies.json
{
"dataProcessing": {
"sortStrategy": "QuickSort",
"validationStrategy": "StrictValidation"
}
}
cpp复制class StrategyLoader {
private:
unordered_map<string, unique_ptr<SortingStrategy>> strategyMap;
public:
void loadFromConfig(const string& configPath) {
// 解析JSON配置文件
ifstream configFile(configPath);
json config = json::parse(configFile);
// 初始化策略映射
strategyMap["QuickSort"] = make_unique<QuickSort>();
strategyMap["MergeSort"] = make_unique<MergeSort>();
// 其他策略初始化...
}
unique_ptr<SortingStrategy> getStrategy(const string& name) {
auto it = strategyMap.find(name);
if(it != strategyMap.end()) {
return it->second->clone(); // 假设策略实现了克隆方法
}
return nullptr;
}
};
4.3 策略的版本管理与热更新
在需要持续运行的系统(如服务器程序)中,实现策略的热更新能力至关重要:
cpp复制class HotSwappableStrategy : public SortingStrategy {
private:
atomic<SortingStrategy*> currentStrategy;
mutex updateMutex;
public:
explicit HotSwappableStrategy(SortingStrategy* initial)
: currentStrategy(initial) {}
void updateStrategy(SortingStrategy* newStrategy) {
lock_guard<mutex> lock(updateMutex);
SortingStrategy* old = currentStrategy.exchange(newStrategy);
delete old; // 安全释放旧策略
}
void sort(vector<int>& data) override {
SortingStrategy* strategy = currentStrategy.load();
strategy->sort(data);
}
~HotSwappableStrategy() {
delete currentStrategy.load();
}
};
在一个分布式计算项目中,我们使用这种热更新机制实现了算法的不停机升级。通过版本控制策略实现,系统可以平滑地从旧算法过渡到新算法,期间不会中断服务。
5. 策略模式与其他模式的协同应用
5.1 策略与模板方法模式结合
模板方法定义算法骨架,策略模式填充具体步骤实现:
cpp复制// 模板方法定义处理流程
class DataProcessor {
protected:
virtual void preprocess(vector<int>& data) = 0;
virtual void sortData(vector<int>& data) = 0;
virtual void postprocess(vector<int>& data) = 0;
public:
void process(vector<int>& data) {
preprocess(data);
sortData(data);
postprocess(data);
}
};
// 使用策略实现具体步骤
class CustomDataProcessor : public DataProcessor {
private:
unique_ptr<SortingStrategy> sorter;
protected:
void preprocess(vector<int>& data) override {
// 预处理逻辑...
}
void sortData(vector<int>& data) override {
if(sorter) sorter->sort(data);
}
void postprocess(vector<int>& data) override {
// 后处理逻辑...
}
public:
void setSorter(unique_ptr<SortingStrategy> newSorter) {
sorter = move(newSorter);
}
};
5.2 策略与装饰器模式结合
装饰器模式可以动态添加策略的附加功能:
cpp复制class SortingDecorator : public SortingStrategy {
protected:
unique_ptr<SortingStrategy> wrapped;
public:
explicit SortingDecorator(unique_ptr<SortingStrategy> strategy)
: wrapped(move(strategy)) {}
void sort(vector<int>& data) override {
wrapped->sort(data);
}
};
class LoggingDecorator : public SortingDecorator {
public:
using SortingDecorator::SortingDecorator;
void sort(vector<int>& data) override {
auto start = chrono::high_resolution_clock::now();
wrapped->sort(data);
auto end = chrono::high_resolution_clock::now();
cout << "Sorting took "
<< chrono::duration_cast<chrono::microseconds>(end-start).count()
<< " μs" << endl;
}
};
// 使用示例
auto strategy = make_unique<LoggingDecorator>(
make_unique<QuickSort>()
);
5.3 策略与观察者模式结合
实现策略执行过程中的状态通知机制:
cpp复制class SortObserver {
public:
virtual void onSortStarted() = 0;
virtual void onSortCompleted() = 0;
virtual ~SortObserver() = default;
};
class ObservableSortStrategy : public SortingStrategy {
private:
vector<SortObserver*> observers;
protected:
void notifyStart() {
for(auto obs : observers) obs->onSortStarted();
}
void notifyEnd() {
for(auto obs : observers) obs->onSortCompleted();
}
public:
void addObserver(SortObserver* observer) {
observers.push_back(observer);
}
void removeObserver(SortObserver* observer) {
observers.erase(remove(observers.begin(), observers.end(), observer),
observers.end());
}
};
class MonitoredQuickSort : public ObservableSortStrategy {
public:
void sort(vector<int>& data) override {
notifyStart();
// 实际的快速排序实现...
notifyEnd();
}
};
在开发一个数据分析平台时,我们结合使用了策略模式、装饰器模式和观察者模式。核心算法采用策略模式实现,性能监控通过装饰器添加,执行状态通过观察者通知UI更新。这种组合使系统获得了极好的扩展性和可维护性。
6. 策略模式在特定领域的深度应用
6.1 游戏开发中的AI行为策略
在游戏AI中,不同NPC可能采用不同的行为策略,且策略可能随游戏状态动态变化:
cpp复制class AIBehavior {
public:
virtual void update(GameEntity& entity, float deltaTime) = 0;
virtual ~AIBehavior() = default;
};
class AggressiveBehavior : public AIBehavior {
public:
void update(GameEntity& entity, float deltaTime) override {
// 寻找最近玩家
// 向玩家移动并攻击
}
};
class DefensiveBehavior : public AIBehavior {
public:
void update(GameEntity& entity, float deltaTime) override {
// 检查自身血量
// 血量低时撤退寻找治疗
}
};
class NeutralBehavior : public AIBehavior {
public:
void update(GameEntity& entity, float deltaTime) override {
// 随机巡逻行为
// 被动响应玩家互动
}
};
class GameEntity {
private:
unique_ptr<AIBehavior> behavior;
public:
void setBehavior(unique_ptr<AIBehavior> newBehavior) {
behavior = move(newBehavior);
}
void update(float deltaTime) {
if(behavior) behavior->update(*this, deltaTime);
}
};
6.2 金融领域的风险评估策略
不同金融产品需要采用不同的风险评估模型,策略模式可以灵活切换评估算法:
cpp复制class RiskAssessment {
public:
virtual double calculateRisk(const Portfolio& portfolio) = 0;
virtual ~RiskAssessment() = default;
};
class VaRModel : public RiskAssessment {
public:
double calculateRisk(const Portfolio& portfolio) override {
// 实现风险价值(VaR)计算
return 0.0;
}
};
class ExpectedShortfall : public RiskAssessment {
public:
double calculateRisk(const Portfolio& portfolio) override {
// 实现预期短缺(ES)计算
return 0.0;
}
};
class StressTesting : public RiskAssessment {
public:
double calculateRisk(const Portfolio& portfolio) override {
// 实现压力测试
return 0.0;
}
};
class RiskManager {
private:
vector<unique_ptr<RiskAssessment>> strategies;
public:
void addStrategy(unique_ptr<RiskAssessment> strategy) {
strategies.push_back(move(strategy));
}
vector<double> assessAllRisks(const Portfolio& portfolio) {
vector<double> results;
for(const auto& strategy : strategies) {
results.push_back(strategy->calculateRisk(portfolio));
}
return results;
}
};
6.3 编译器优化的策略应用
现代编译器通常提供多种优化级别,本质上就是不同的优化策略组合:
cpp复制class OptimizationPass {
public:
virtual void apply(IRModule& module) = 0;
virtual ~OptimizationPass() = default;
};
class ConstantFolding : public OptimizationPass {
public:
void apply(IRModule& module) override {
// 实现常量折叠优化
}
};
class DeadCodeElimination : public OptimizationPass {
public:
void apply(IRModule& module) override {
// 实现死代码消除
}
};
class InliningPass : public OptimizationPass {
public:
void apply(IRModule& module) override {
// 实现函数内联
}
};
class Optimizer {
private:
vector<unique_ptr<OptimizationPass>> passes;
public:
void addPass(unique_ptr<OptimizationPass> pass) {
passes.push_back(move(pass));
}
void optimize(IRModule& module) {
for(const auto& pass : passes) {
pass->apply(module);
}
}
static unique_ptr<Optimizer> createForLevel(OptimizationLevel level) {
auto optimizer = make_unique<Optimizer>();
switch(level) {
case O0: // 无优化
break;
case O1:
optimizer->addPass(make_unique<ConstantFolding>());
break;
case O2:
optimizer->addPass(make_unique<ConstantFolding>());
optimizer->addPass(make_unique<DeadCodeElimination>());
break;
case O3:
optimizer->addPass(make_unique<ConstantFolding>());
optimizer->addPass(make_unique<DeadCodeElimination>());
optimizer->addPass(make_unique<InliningPass>());
break;
}
return optimizer;
}
};
在参与开发一个C++静态分析工具时,我们采用了类似的策略架构。用户可以选择不同的分析策略组合,每个策略专注于特定类型的代码问题检测。这种设计使得添加新的分析规则变得非常简单,只需实现新的策略类并注册到系统中即可。
7. 策略模式的测试与调试技巧
7.1 策略接口的单元测试
为策略接口设计全面的测试用例,确保所有实现策略符合预期行为:
cpp复制TEST(SortingStrategyTest, QuickSortSortsCorrectly) {
QuickSort sorter;
vector<int> data = {5, 3, 8, 1, 2};
vector<int> expected = {1, 2, 3, 5, 8};
sorter.sort(data);
ASSERT_EQ(data, expected);
}
TEST(SortingStrategyTest, MergeSortSortsCorrectly) {
MergeSort sorter;
vector<int> data = {5, 3, 8, 1, 2};
vector<int> expected = {1, 2, 3, 5, 8};
sorter.sort(data);
ASSERT_EQ(data, expected);
}
TEST(SortContextTest, CanSwitchStrategies) {
SortContext ctx;
vector<int> data = {5, 3, 8, 1, 2};
vector<int> expected = {1, 2, 3, 5, 8};
ctx.setStrategy(make_unique<QuickSort>());
ctx.executeSort(data);
ASSERT_EQ(data, expected);
data = {5, 3, 8, 1, 2}; // 重置测试数据
ctx.setStrategy(make_unique<MergeSort>());
ctx.executeSort(data);
ASSERT_EQ(data, expected);
}
7.2 策略的模拟与依赖注入
在测试上下文类时,使用模拟策略隔离被测代码:
cpp复制class MockSortingStrategy : public SortingStrategy {
public:
MOCK_METHOD(void, sort, (vector<int>&), (override));
};
TEST(SortContextTest, ExecutesCurrentStrategy) {
SortContext ctx;
MockSortingStrategy mockStrategy;
vector<int> testData = {1, 2, 3};
EXPECT_CALL(mockStrategy, sort(testData)).Times(1);
ctx.setStrategy(make_unique<MockSortingStrategy>());
ctx.executeSort(testData);
}
7.3 策略的性能分析与调优
使用性能分析工具评估不同策略的实际表现:
cpp复制void benchmarkStrategy(unique_ptr<SortingStrategy> strategy,
const vector<int>& testData) {
auto data = testData; // 创建数据副本
auto start = chrono::high_resolution_clock::now();
strategy->sort(data);
auto end = chrono::high_resolution_clock::now();
auto duration = chrono::duration_cast<chrono::microseconds>(end-start);
cout << "Sorting took " << duration.count() << " μs" << endl;
}
// 使用示例
vector<int> largeData(1000000);
generate(largeData.begin(), largeData.end(), rand);
benchmarkStrategy(make_unique<QuickSort>(), largeData);
benchmarkStrategy(make_unique<MergeSort>(), largeData);
7.4 策略的内存与资源分析
检查策略实现是否存在内存泄漏或资源管理问题:
cpp复制class LeakCheckStrategy : public SortingStrategy {
private:
static int instanceCount;
public:
LeakCheckStrategy() { ++instanceCount; }
~LeakCheckStrategy() { --instanceCount; }
void sort(vector<int>&) override {}
static int getCount() { return instanceCount; }
};
int LeakCheckStrategy::instanceCount = 0;
TEST(StrategyMemoryTest, NoLeakOnStrategySwitch) {
SortContext ctx;
{
ctx.setStrategy(make_unique<LeakCheckStrategy>());
EXPECT_EQ(LeakCheckStrategy::getCount(), 1);
ctx.setStrategy(make_unique<LeakCheckStrategy>());
EXPECT_EQ(LeakCheckStrategy::getCount(), 1); // 前一个应被正确释放
}
EXPECT_EQ(LeakCheckStrategy::getCount(), 0);
}
在开发一个实时数据处理系统时,我们通过类似的性能基准测试发现,某些策略在特定数据分布下表现不佳。基于这些发现,我们实现了自适应策略选择机制,系统会根据输入数据特征自动选择最优处理策略。
8. C++20/23新特性对策略模式的增强
8.1 概念(Concepts)约束策略接口
使用C++20概念确保策略类满足接口要求:
cpp复制template<typename T>
concept SortingStrategy = requires(T s, vector<int> data) {
{ s.sort(data) } -> same_as<void>;
requires is_default_constructible_v<T>;
};
template<SortingStrategy T>
class SortContext {
private:
T strategy;
public:
void executeSort(vector<int>& data) {
strategy.sort(data);
}
};
// 使用示例
SortContext<QuickSort> ctx; // 编译通过
// SortContext<string> ctx; // 编译错误:不满足概念约束
8.2 使用std::function实现轻量级策略
结合C++11的std::function实现更灵活的策略模式:
cpp复制class SortContext {
private:
function<void(vector<int>&)> strategy;
public:
template<typename T>
void setStrategy(T&& s) {
strategy = forward<T>(s);
}
void executeSort(vector<int>& data) {
if(strategy) strategy(data);
}
};
// 使用示例
SortContext ctx;
ctx.setStrategy([](vector<int>& data) {
sort(data.begin(), data.end());
});
vector<int> data = {5, 2, 8, 1};
ctx.executeSort(data);
8.3 协程与异步策略
在C++20协程支持下,实现异步处理策略:
cpp复制class AsyncStrategy {
public:
virtual future<void> processAsync(vector<int>& data) = 0;
virtual ~AsyncStrategy() = default;
};
class ParallelSort : public AsyncStrategy {
public:
future<void> processAsync(vector<int>& data) override {
co_await async(launch::async, [&data] {
sort(data.begin(), data.end());
});
}
};
class AsyncContext {
private:
unique_ptr<AsyncStrategy> strategy;
public:
void setStrategy(unique_ptr<AsyncStrategy> newStrategy) {
strategy = move(newStrategy);
}
future<void> executeAsync(vector<int>& data) {
if(strategy) {
co_await strategy->processAsync(data);
}
}
};
8.4 使用span优化策略性能
C++20的span可以避免策略实现中的数据拷贝:
cpp复制class SpanBasedStrategy {
public:
virtual void process(span<int> data) = 0;
virtual ~SpanBasedStrategy() = default;
};
class FastProcessing : public SpanBasedStrategy {
public:
void process(span<int> data) override {
// 直接操作连续内存,无需拷贝
for(auto& item : data) {
item *= 2;
}
}
};
class SpanContext {
private:
unique_ptr<SpanBasedStrategy> strategy;
public:
void setStrategy(unique_ptr<SpanBasedStrategy> newStrategy) {
strategy = move(newStrategy);
}
void execute(span<int> data) {
if(strategy) strategy->process(data);
}
};
在最近的一个高性能计算项目中,我们利用C++20的这些新特性重构了原有的策略实现。概念约束使接口要求更明确,span避免了不必要的数据拷贝,协程支持使异步策略的实现更加简洁。这些改进使系统性能提升了约15%,同时代码的可维护性也得到了显著提高。
