1. 策略模式在C++中的核心价值与应用场景
策略模式(Strategy Pattern)是我在十多年C++开发中最常使用的设计模式之一。它本质上定义了一系列算法族,将每个算法封装起来,使它们可以互相替换。这种模式让算法的变化独立于使用算法的客户。
想象你正在开发一个游戏角色系统。不同角色使用不同武器(剑、弓箭、魔法),每种武器都有独特的攻击方式。硬编码每种武器的攻击逻辑会导致代码臃肿且难以维护。这时策略模式就能完美解决问题:
cpp复制class WeaponStrategy {
public:
virtual void attack() = 0;
virtual ~WeaponStrategy() = default;
};
class SwordStrategy : public WeaponStrategy {
public:
void attack() override {
std::cout << "Swing sword!" << std::endl;
}
};
class Character {
std::unique_ptr<WeaponStrategy> weapon;
public:
void setWeapon(std::unique_ptr<WeaponStrategy> newWeapon) {
weapon = std::move(newWeapon);
}
void performAttack() {
if(weapon) weapon->attack();
}
};
这种设计带来的核心优势:
- 开闭原则:新增武器类型只需添加新策略类,无需修改现有代码
- 消除条件语句:避免大量if-else或switch-case判断武器类型
- 运行时灵活性:角色可以在运行时切换武器策略
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 策略模式的经典实现与内存管理
在C++中实现策略模式需要特别注意资源管理。我推荐使用std::unique_ptr来持有策略对象,这能明确所有权关系并防止内存泄漏。以下是银行系统中不同利率计算策略的示例:
cpp复制class InterestStrategy {
public:
virtual double calculate(double balance) const = 0;
virtual ~InterestStrategy() = default;
};
class RegularInterest : public InterestStrategy {
public:
double calculate(double balance) const override {
return balance * 0.02; // 2%年利率
}
};
class VIPInterest : public InterestStrategy {
public:
double calculate(double balance) const override {
return balance * 0.05; // 5%年利率
}
};
class Account {
std::unique_ptr<InterestStrategy> strategy;
double balance;
public:
Account(std::unique_ptr<InterestStrategy> s, double initial)
: strategy(std::move(s)), balance(initial) {}
void setStrategy(std::unique_ptr<InterestStrategy> newStrategy) {
strategy = std::move(newStrategy);
}
double calculateInterest() const {
return strategy->calculate(balance);
}
};
重要提示:策略接口必须包含虚析构函数!否则通过基类指针删除派生类对象会导致资源泄漏。
3. 现代C++中的策略模式优化
C++11后的新特性让策略模式实现更加优雅。以下是三种现代改进方案:
3.1 使用std::function替代继承
cpp复制class PaymentProcessor {
using PaymentStrategy = std::function<bool(double)>;
PaymentStrategy strategy;
public:
void setStrategy(PaymentStrategy s) { strategy = s; }
bool processPayment(double amount) {
return strategy ? strategy(amount) : false;
}
};
// 使用lambda定义策略
auto creditCardStrategy = [](double amount) {
std::cout << "Processing $" << amount << " via Credit Card" << std::endl;
return true;
};
PaymentProcessor processor;
processor.setStrategy(creditCardStrategy);
processor.processPayment(99.99);
3.2 策略模式与模板结合
cpp复制template<typename Strategy>
class Context {
Strategy strategy;
public:
void execute() { strategy.doAlgorithm(); }
};
struct ConcreteStrategyA {
void doAlgorithm() { std::cout << "Using Strategy A\n"; }
};
Context<ConcreteStrategyA> context;
context.execute();
3.3 使用type-erasure技术
cpp复制class AnyStrategy {
struct Concept {
virtual ~Concept() = default;
virtual void execute() = 0;
};
template<typename T>
struct Model : Concept {
T impl;
Model(T t) : impl(std::move(t)) {}
void execute() override { impl.execute(); }
};
std::unique_ptr<Concept> pimpl;
public:
template<typename T>
AnyStrategy(T t) : pimpl(new Model<T>(std::move(t))) {}
void execute() { pimpl->execute(); }
};
4. 实战案例:电商促销系统设计
假设我们要实现一个电商促销系统,支持多种折扣策略。以下是经过生产环境验证的实现:
cpp复制class DiscountStrategy {
public:
virtual double applyDiscount(double originalPrice) = 0;
virtual ~DiscountStrategy() = default;
};
class NoDiscount : public DiscountStrategy {
public:
double applyDiscount(double price) override { return price; }
};
class PercentageDiscount : public DiscountStrategy {
double percentage;
public:
explicit PercentageDiscount(double p) : percentage(p) {}
double applyDiscount(double price) override {
return price * (1 - percentage/100);
}
};
class Order {
std::unique_ptr<DiscountStrategy> strategy;
double total;
public:
Order() : strategy(std::make_unique<NoDiscount>()), total(0) {}
void setDiscountStrategy(std::unique_ptr<DiscountStrategy> s) {
strategy = std::move(s);
}
void addItem(double price) { total += price; }
double calculateTotal() {
return strategy->applyDiscount(total);
}
};
典型使用场景:
cpp复制Order order;
order.addItem(100);
order.addItem(50);
// 应用20%折扣
order.setDiscountStrategy(std::make_unique<PercentageDiscount>(20));
std::cout << "Discounted total: " << order.calculateTotal(); // 输出120
5. 性能考量与优化技巧
在性能敏感场景中,策略模式可能带来间接调用开销。以下是我总结的优化方案:
5.1 策略对象复用
cpp复制// 单例策略对象
class FreeShippingStrategy : public DiscountStrategy {
static FreeShippingStrategy instance;
public:
static FreeShippingStrategy& getInstance() { return instance; }
double applyDiscount(double price) override {
return price - 10; // 减免10元运费
}
};
// 使用时
order.setDiscountStrategy(std::unique_ptr<DiscountStrategy>(
&FreeShippingStrategy::getInstance(),
[](DiscountStrategy*){} // 空删除器
));
5.2 CRTP静态策略模式
cpp复制template<typename Derived>
class StaticDiscountStrategy {
public:
double applyDiscount(double price) {
return static_cast<Derived*>(this)->applyDiscountImpl(price);
}
};
class MemberDiscount : public StaticDiscountStrategy<MemberDiscount> {
friend class StaticDiscountStrategy<MemberDiscount>;
double applyDiscountImpl(double price) {
return price * 0.9; // 会员9折
}
};
template<typename Strategy>
class StaticOrder {
Strategy strategy;
double total;
public:
void addItem(double price) { total += price; }
double calculateTotal() { return strategy.applyDiscount(total); }
};
5.3 策略模式与数据驱动设计结合
cpp复制class DiscountStrategyFactory {
std::unordered_map<std::string, std::function<std::unique_ptr<DiscountStrategy>()>> creators;
public:
DiscountStrategyFactory() {
creators["percentage"] = [] { return std::make_unique<PercentageDiscount>(10); };
creators["fixed"] = [] { return std::make_unique<FixedAmountDiscount>(5); };
}
std::unique_ptr<DiscountStrategy> create(const std::string& type) {
auto it = creators.find(type);
return it != creators.end() ? it->second() : nullptr;
}
};
6. 常见陷阱与调试技巧
6.1 策略对象生命周期管理
我曾在一个项目中遇到策略对象被意外销毁的问题。解决方案是:
- 使用
shared_ptr当策略需要共享时 - 明确文档说明策略对象的生命周期要求
- 在策略接口中添加
clone()方法支持深拷贝
cpp复制class CloneableStrategy {
public:
virtual std::unique_ptr<CloneableStrategy> clone() const = 0;
virtual ~CloneableStrategy() = default;
};
class ConcreteStrategy : public CloneableStrategy {
public:
std::unique_ptr<CloneableStrategy> clone() const override {
return std::make_unique<ConcreteStrategy>(*this);
}
};
6.2 多线程环境下的策略模式
策略对象如果包含可变状态,需要特别注意线程安全:
- 将策略设计为不可变对象(最佳实践)
- 使用互斥锁保护可变状态
- 避免在策略接口中使用静态变量
cpp复制class ThreadSafeStrategy {
mutable std::mutex mtx;
double state;
public:
double execute() const {
std::lock_guard<std::mutex> lock(mtx);
// 使用state进行计算
return state * 2;
}
};
6.3 策略模式与其它模式的组合
在实际项目中,策略模式常与其他模式配合使用:
策略+工厂模式
cpp复制class StrategyFactory {
public:
static std::unique_ptr<Strategy> create(const std::string& config) {
if(config == "A") return std::make_unique<StrategyA>();
if(config == "B") return std::make_unique<StrategyB>();
throw std::invalid_argument("Unknown strategy type");
}
};
策略+装饰器模式
cpp复制class DecoratedStrategy : public Strategy {
std::unique_ptr<Strategy> wrapped;
public:
explicit DecoratedStrategy(std::unique_ptr<Strategy> s) : wrapped(std::move(s)) {}
void execute() override {
preProcess();
wrapped->execute();
postProcess();
}
};
7. 测试策略模式的实用技巧
为策略模式编写单元测试时,我推荐以下方法:
7.1 模拟策略对象
cpp复制class MockStrategy : public StrategyInterface {
public:
MOCK_METHOD(void, execute, (), (override));
};
TEST(ContextTest, ExecutesStrategy) {
MockStrategy mock;
Context context(mock);
EXPECT_CALL(mock, execute()).Times(1);
context.run();
}
7.2 测试策略组合
cpp复制TEST(DiscountTest, CombinedStrategies) {
Order order;
order.addItem(100);
order.setDiscountStrategy(std::make_unique<PercentageDiscount>(10));
ASSERT_EQ(order.calculateTotal(), 90);
order.setDiscountStrategy(std::make_unique<FixedAmountDiscount>(20));
ASSERT_EQ(order.calculateTotal(), 80);
}
7.3 性能基准测试
cpp复制static void BM_StrategyPattern(benchmark::State& state) {
Context context(std::make_unique<ConcreteStrategy>());
for(auto _ : state) {
context.execute();
}
}
BENCHMARK(BM_StrategyPattern);
