策略模式(Strategy)是行为型设计模式的一种,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。这种模式让算法的变化独立于使用算法的客户端,从而实现算法的灵活切换。
一、核心思想与角色
策略模式的核心是"算法封装与动态切换",通过将不同算法分离为独立的策略类,使客户端可以根据需求选择或切换算法。其核心角色如下:
角色名称 | 核心职责 |
---|---|
抽象策略(Strategy) | 定义所有支持的算法的公共接口,声明算法的执行方法。 |
具体策略(ConcreteStrategy) | 实现抽象策略接口,包含具体的算法逻辑。 |
环境类(Context) | 持有一个策略对象的引用,提供设置策略的接口,在需要时调用策略的执行方法。 |
核心思想:将算法的定义与使用分离,客户端通过环境类间接使用策略,可在运行时动态更换策略,而无需修改使用算法的代码。
二、实现示例(支付方式选择)
假设我们需要设计一个电商支付系统,支持多种支付方式(如支付宝、微信支付、银联支付),用户可根据需求选择不同支付方式。使用策略模式可将每种支付方式封装为独立策略,实现灵活切换:
cpp
#include <iostream>
#include <string>
// 1. 抽象策略:支付方式
class PaymentStrategy {
public:
// 纯虚方法:执行支付
virtual void pay(double amount) = 0;
virtual ~PaymentStrategy() = default;
};
// 2. 具体策略1:支付宝支付
class AlipayStrategy : public PaymentStrategy {
private:
std::string account; // 支付宝账号
public:
AlipayStrategy(const std::string& acc) : account(acc) {}
void pay(double amount) override {
std::cout << "使用支付宝账号[" << account << "]支付了 " << amount << " 元" << std::endl;
// 实际支付逻辑:调用支付宝API...
}
};
// 2. 具体策略2:微信支付
class WechatPayStrategy : public PaymentStrategy {
private:
std::string openId; // 微信OpenID
public:
WechatPayStrategy(const std::string& id) : openId(id) {}
void pay(double amount) override {
std::cout << "使用微信OpenID[" << openId << "]支付了 " << amount << " 元" << std::endl;
// 实际支付逻辑:调用微信支付API...
}
};
// 2. 具体策略3:银联支付
class UnionPayStrategy : public PaymentStrategy {
private:
std::string cardNumber; // 银行卡号
public:
UnionPayStrategy(const std::string& card) : cardNumber(card) {}
void pay(double amount) override {
std::cout << "使用银联卡[" << cardNumber << "]支付了 " << amount << " 元" << std::endl;
// 实际支付逻辑:调用银联API...
}
};
// 3. 环境类:订单支付上下文
class PaymentContext {
private:
PaymentStrategy* strategy; // 当前支付策略
public:
// 构造时指定初始策略
PaymentContext(PaymentStrategy* strat) : strategy(strat) {}
// 动态更换支付策略
void setStrategy(PaymentStrategy* newStrat) {
strategy = newStrat;
}
// 执行支付(委托给当前策略)
void pay(double amount) {
if (strategy) {
strategy->pay(amount);
} else {
std::cout << "未设置支付方式,支付失败" << std::endl;
}
}
};
// 客户端代码:使用支付系统
int main() {
// 创建具体支付策略
PaymentStrategy* alipay = new AlipayStrategy("user123@alipay.com");
PaymentStrategy* wechat = new WechatPayStrategy("o6_bmjrPTlm6_2sgVt7hMZOPfL2M");
PaymentStrategy* unionpay = new UnionPayStrategy("6222 **** **** 1234");
// 创建支付上下文(环境类),初始使用支付宝
PaymentContext* payment = new PaymentContext(alipay);
// 支付订单1
std::cout << "=== 订单1支付 ===" << std::endl;
payment->pay(99.9);
// 切换为微信支付,支付订单2
std::cout << "\n=== 订单2支付 ===" << std::endl;
payment->setStrategy(wechat);
payment->pay(199.5);
// 切换为银联支付,支付订单3
std::cout << "\n=== 订单3支付 ===" << std::endl;
payment->setStrategy(unionpay);
payment->pay(599.0);
// 释放资源
delete unionpay;
delete wechat;
delete alipay;
delete payment;
return 0;
}
三、代码解析
-
抽象策略(PaymentStrategy) :
定义了
pay()
纯虚方法,声明所有支付方式必须实现的支付接口,参数为支付金额。 -
具体策略 :
每种支付方式对应一个具体策略类,实现
pay()
方法封装各自的支付逻辑:AlipayStrategy
:支付宝支付,需要支付宝账号。WechatPayStrategy
:微信支付,需要微信OpenID。UnionPayStrategy
:银联支付,需要银行卡号。
每个策略类专注于自身的支付实现,与其他策略相互独立。
-
环境类(PaymentContext):
- 持有当前支付策略的引用(
strategy
),通过setStrategy()
方法支持动态切换策略。 - 提供
pay()
方法,将支付操作委托给当前策略的pay()
方法,客户端无需直接调用策略。
- 持有当前支付策略的引用(
-
客户端使用 :
客户端创建具体策略和环境类,通过环境类执行支付;需要更换支付方式时,调用
setStrategy()
切换策略,无需修改支付逻辑代码。
四、核心优势与适用场景
优势
- 算法解耦:将算法与使用算法的客户端分离,算法的修改或新增不影响客户端。
- 动态切换:支持在运行时动态更换算法(如示例中切换支付方式),灵活性高。
- 代码复用:不同环境可共享同一策略对象,避免代码重复。
- 符合开闭原则:新增算法只需添加新的策略类,无需修改现有代码。
- 替代条件判断 :用策略选择替代
if-else
或switch-case
,使代码更清晰。
适用场景
- 多种算法可选:如排序算法(快速排序、冒泡排序)、支付方式、折扣计算方式。
- 算法需要动态切换:如根据用户设置切换压缩算法、根据网络状况切换传输协议。
- 避免算法与客户端耦合:如框架设计中允许用户自定义插件(策略)。
- 算法逻辑复杂:当算法包含多个步骤或变体时,封装为策略可提高可读性。
五、与其他模式的区别
模式 | 核心差异点 |
---|---|
策略模式 | 封装可互换的算法,客户端可动态选择,强调"算法替换"。 |
状态模式 | 封装对象的状态,状态决定行为且可自动转换,强调"状态驱动行为"。 |
模板方法 | 定义算法骨架,子类实现具体步骤,强调"固定流程+可变步骤"。 |
工厂模式 | 用于创建对象,可与策略模式结合(工厂创建策略对象),但不涉及算法执行。 |
六、实践建议
- 策略工厂结合 :使用工厂模式创建策略对象,减少客户端对具体策略的依赖(如
PaymentStrategyFactory
根据类型创建支付策略)。 - 策略缓存复用:对于无状态的策略(如无成员变量的算法),可缓存策略对象避免重复创建(类似单例)。
- 策略参数化 :通过构造函数或
setter
方法为策略传递参数(如示例中的账号信息),提高灵活性。 - 避免策略膨胀:当策略过多时,可结合享元模式共享策略对象,或使用组合模式拆分复杂策略。
策略模式的核心价值在于"算法的模块化与动态化",它通过将算法封装为独立策略,使系统能灵活适应算法的变化,同时保持客户端代码的稳定。在需要提供多种可选方案或算法可能频繁变更的场景中,策略模式是实现代码灵活性和可维护性的理想选择。