1. 策略模式概述
策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。这种模式让算法的变化独立于使用算法的客户端。
在实际开发中,我们经常会遇到这样的情况:某个功能可能有多种实现方式,或者某个业务逻辑在不同场景下需要采用不同的算法。比如电商系统中的折扣策略(满减、折扣券、会员价)、支付方式(支付宝、微信、银联)、排序算法(快速排序、归并排序、堆排序)等场景。
策略模式的核心思想是将算法与使用算法的客户端解耦,通过组合(委托)而非继承的方式来实现行为的动态切换。
2. 策略模式结构解析
2.1 类图结构
策略模式通常包含以下三个核心角色:
- Context(上下文):持有一个Strategy对象的引用,负责与Strategy交互的接口
- Strategy(抽象策略):定义所有支持的算法的公共接口
- ConcreteStrategy(具体策略):实现Strategy接口的具体算法类
cpp复制// 策略接口
class Strategy {
public:
virtual void execute() = 0;
virtual ~Strategy() = default;
};
// 具体策略A
class ConcreteStrategyA : public Strategy {
public:
void execute() override {
// 实现A的具体算法
}
};
// 具体策略B
class ConcreteStrategyB : public Strategy {
public:
void execute() override {
// 实现B的具体算法
}
};
// 上下文
class Context {
private:
Strategy* strategy;
public:
Context(Strategy* s) : strategy(s) {}
void setStrategy(Strategy* s) {
strategy = s;
}
void executeStrategy() {
strategy->execute();
}
~Context() {
delete strategy;
}
};
2.2 模式特点
- 开闭原则:可以在不修改现有代码的情况下引入新策略
- 消除条件语句:避免使用大量的if-else或switch-case语句
- 运行时灵活性:可以在运行时动态切换算法
- 代码复用:多个上下文可以共享同一个策略对象
3. 策略模式实现细节
3.1 上下文类的实现要点
上下文类是策略模式的关键,它需要:
- 持有策略对象的指针或引用
- 提供设置策略的方法(可选)
- 提供执行策略的接口
- 负责策略对象的生命周期管理(如果拥有所有权)
cpp复制class PaymentContext {
private:
PaymentStrategy* strategy;
public:
// 设置支付策略
void setStrategy(PaymentStrategy* s) {
if(strategy) delete strategy;
strategy = s;
}
// 执行支付
void executePayment(double amount) {
if(strategy) {
strategy->pay(amount);
} else {
throw std::runtime_error("Payment strategy not set");
}
}
~PaymentContext() {
delete strategy;
}
};
3.2 策略接口设计原则
- 单一职责:每个策略类应该只负责一个具体的算法实现
- 接口隔离:策略接口应该尽可能小,只包含必要的方法
- 无状态性:理想情况下策略对象应该是无状态的,可以被多个上下文共享
4. 策略模式实战应用
4.1 电商折扣系统实现
假设我们要实现一个电商平台的折扣系统,支持多种折扣策略:
cpp复制// 折扣策略接口
class DiscountStrategy {
public:
virtual double applyDiscount(double originalPrice) = 0;
virtual ~DiscountStrategy() = default;
};
// 无折扣
class NoDiscount : public DiscountStrategy {
public:
double applyDiscount(double originalPrice) override {
return originalPrice;
}
};
// 固定折扣
class FixedDiscount : public DiscountStrategy {
private:
double discountRate;
public:
FixedDiscount(double rate) : discountRate(rate) {}
double applyDiscount(double originalPrice) override {
return originalPrice * (1 - discountRate);
}
};
// 满减折扣
class ThresholdDiscount : public DiscountStrategy {
private:
double threshold;
double discountAmount;
public:
ThresholdDiscount(double t, double amount)
: threshold(t), discountAmount(amount) {}
double applyDiscount(double originalPrice) override {
if(originalPrice >= threshold) {
return originalPrice - discountAmount;
}
return originalPrice;
}
};
// 订单上下文
class Order {
private:
DiscountStrategy* discountStrategy;
double totalPrice;
public:
Order(double price, DiscountStrategy* strategy)
: totalPrice(price), discountStrategy(strategy) {}
void setDiscountStrategy(DiscountStrategy* strategy) {
discountStrategy = strategy;
}
double calculateFinalPrice() {
return discountStrategy->applyDiscount(totalPrice);
}
~Order() {
delete discountStrategy;
}
};
4.2 支付系统实现
另一个典型应用是支付系统的实现:
cpp复制// 支付策略接口
class PaymentStrategy {
public:
virtual void pay(double amount) = 0;
virtual ~PaymentStrategy() = default;
};
// 支付宝支付
class AlipayStrategy : public PaymentStrategy {
public:
void pay(double amount) override {
std::cout << "使用支付宝支付: " << amount << "元" << std::endl;
// 实际的支付宝支付逻辑
}
};
// 微信支付
class WechatPayStrategy : public PaymentStrategy {
public:
void pay(double amount) override {
std::cout << "使用微信支付: " << amount << "元" << std::endl;
// 实际的微信支付逻辑
}
};
// 银联支付
class UnionPayStrategy : public PaymentStrategy {
public:
void pay(double amount) override {
std::cout << "使用银联支付: " << amount << "元" << std::endl;
// 实际的银联支付逻辑
}
};
5. 策略模式高级应用
5.1 策略工厂模式
结合工厂模式可以更好地管理策略对象的创建:
cpp复制class StrategyFactory {
public:
static Strategy* createStrategy(const std::string& type) {
if(type == "A") {
return new ConcreteStrategyA();
} else if(type == "B") {
return new ConcreteStrategyB();
}
return nullptr;
}
};
// 使用示例
Context ctx(StrategyFactory::createStrategy("A"));
ctx.executeStrategy();
5.2 策略模式与模板方法模式对比
策略模式和模板方法模式都用于封装算法,但实现方式不同:
| 特性 | 策略模式 | 模板方法模式 |
|---|---|---|
| 实现方式 | 组合/委托 | 继承 |
| 灵活性 | 运行时动态切换 | 编译时确定 |
| 代码复用 | 策略对象可被多个上下文共享 | 通过父类复用公共代码 |
| 适用场景 | 算法需要频繁切换 | 算法骨架固定,部分步骤可变 |
6. 策略模式最佳实践
6.1 性能优化考虑
- 策略对象复用:如果策略对象是无状态的,可以设计为单例或静态对象
- 避免频繁创建销毁:使用对象池管理策略对象
- 内存管理:使用智能指针自动管理策略对象生命周期
cpp复制// 使用shared_ptr管理策略对象
class Context {
private:
std::shared_ptr<Strategy> strategy;
public:
Context(std::shared_ptr<Strategy> s) : strategy(s) {}
void executeStrategy() {
strategy->execute();
}
};
6.2 设计注意事项
- 策略接口设计:确保接口足够通用,能适应各种具体策略
- 上下文设计:上下文类应该尽可能简单,不包含业务逻辑
- 策略选择机制:考虑如何选择合适的策略(工厂、配置、依赖注入等)
- 默认策略:提供一个合理的默认策略实现
7. 常见问题与解决方案
7.1 策略选择问题
问题:如何根据运行时条件选择合适的策略?
解决方案:
- 使用简单工厂模式创建策略对象
- 通过配置文件指定策略
- 使用依赖注入框架管理策略
cpp复制// 基于配置的策略选择
Strategy* createStrategyFromConfig(const Config& config) {
std::string strategyType = config.get("strategy_type");
if(strategyType == "A") return new ConcreteStrategyA();
if(strategyType == "B") return new ConcreteStrategyB();
return new DefaultStrategy();
}
7.2 策略组合问题
问题:如何实现多个策略的组合使用?
解决方案:
- 创建组合策略类,内部维护多个策略对象
- 定义策略组合规则(顺序执行、条件执行等)
cpp复制class CompositeStrategy : public Strategy {
private:
std::vector<Strategy*> strategies;
public:
void addStrategy(Strategy* s) {
strategies.push_back(s);
}
void execute() override {
for(auto s : strategies) {
s->execute();
}
}
~CompositeStrategy() {
for(auto s : strategies) {
delete s;
}
}
};
7.3 策略与状态模式混淆
问题:策略模式和状态模式看起来很相似,如何区分?
区别:
- 目的不同:策略模式封装算法,状态模式封装状态行为
- 切换机制:策略切换通常由客户端控制,状态转换由状态对象自身控制
- 关注点:策略关注算法替换,状态关注状态转换
在实际项目中,我经常遇到需要根据不同的业务场景选择不同算法的情况。策略模式提供了一种清晰的方式来组织这些算法,使代码更易于维护和扩展。特别是在支付系统、折扣计算、数据验证等场景下,策略模式能够显著提高代码的灵活性和可测试性。
一个实用的技巧是将策略模式与工厂模式结合使用,通过配置文件来指定具体的策略实现,这样可以在不修改代码的情况下调整系统行为。另外,对于无状态的策略对象,可以考虑将其设计为单例或静态对象以提高性能。