策略模式
策略模式(Strategy Pattern)是一种行为型设计模式,它允许在运行时动态选择算法或行为,通过将一系列可互换的算法封装到独立的策略类中,使客户端代码可以灵活地切换不同策略。它强调行为的封装和替换,常用于需要根据不同条件选择不同实现逻辑的场景。
策略模式的组成
策略模式通常包含以下几个角色:
- 上下文(Context):持有策略对象的引用,并提供接口供客户端调用,负责将请求委托给当前策略。
- 策略接口(Strategy):定义所有具体策略的公共接口,声明策略方法。
- 具体策略(Concrete Strategy):实现策略接口,定义具体的算法或行为。
- 客户端(Client):创建并配置上下文对象,设置具体的策略。
工作原理
- 客户端选择一个具体策略并将其注入上下文。
- 上下文通过策略接口调用方法,具体行为由当前策略对象执行。
- 客户端可以在运行时动态更换策略,改变上下文的行为。
UML 类图
┌────────────────┐
│ Context │
├────────────────┤
│ strategy │
│ setStrategy() │
│ execute() │
└────────────────┘
↑
│
┌────────────────┐
│ Strategy │
├────────────────┤
│ execute() │
└────────────────┘
↑
│
┌────────────────┐ ┌────────────────┐
│ ConcreteStrategyA │ │ ConcreteStrategyB │
├────────────────┤ ├────────────────┤
│ execute() │ │ execute() │
└────────────────┘ └────────────────┘
代码示例(以 Java 为例)
以下是一个策略模式的实现,模拟不同支付方式的场景:
// 策略接口
interface PaymentStrategy {
void pay(double amount);
}
// 具体策略:信用卡支付
class CreditCardPayment implements PaymentStrategy {
private String cardNumber;
public CreditCardPayment(String cardNumber) {
this.cardNumber = cardNumber;
}
@Override
public void pay(double amount) {
System.out.println("使用信用卡 " + cardNumber + " 支付 " + amount + " 元");
}
}
// 具体策略:支付宝支付
class AlipayPayment implements PaymentStrategy {
private String account;
public AlipayPayment(String account) {
this.account = account;
}
@Override
public void pay(double amount) {
System.out.println("使用支付宝 " + account + " 支付 " + amount + " 元");
}
}
// 上下文:支付上下文
class PaymentContext {
private PaymentStrategy strategy;
public void setStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void executePayment(double amount) {
if (strategy == null) {
System.out.println("请先选择支付方式");
return;
}
strategy.pay(amount);
}
}
// 测试代码
public class Main {
public static void main(String[] args) {
PaymentContext context = new PaymentContext();
// 使用信用卡支付
context.setStrategy(new CreditCardPayment("1234-5678-9012-3456"));
context.executePayment(100.0);
// 切换到支付宝支付
context.setStrategy(new AlipayPayment("user@example.com"));
context.executePayment(200.0);
}
}
输出:
使用信用卡 1234-5678-9012-3456 支付 100.0 元
使用支付宝 user@example.com 支付 200.0 元
策略模式的特点
- 优点:
- 将算法或行为封装到独立类中,符合单一职责原则。
- 支持运行时动态切换策略,灵活性高。
- 替代了大量的条件语句(如
if-else
或switch
),提高代码可读性和维护性。 - 符合开闭原则,新增策略只需添加新的具体策略类。
- 缺点:
- 如果策略数量较多,会增加类的数量,系统复杂度可能上升。
- 客户端需要了解所有策略的实现细节以选择合适的策略。
使用场景
- 当需要根据不同条件选择不同算法或行为时:
- 支付系统(如信用卡、支付宝、微信支付)。
- 排序算法(如快速排序、归并排序)。
- 压缩算法(如 ZIP、RAR)。
- 需要动态切换行为或算法的场景:
- 游戏中角色的攻击方式(如近战、远程)。
- 日志记录方式(如文件日志、数据库日志)。
- 替代大量条件语句的场景。
注意事项
- 与状态模式的区别:
- 策略模式侧重于选择不同的算法或行为,策略间通常独立,无状态转换。
- 状态模式侧重于根据对象状态切换行为,状态间可能存在转换关系。
- 策略的选择:可以由客户端显式设置策略,也可以通过工厂模式自动选择策略以降低客户端的负担。
- 复用性:策略对象通常无状态,可使用单例模式或静态实例以减少内存开销。
- 扩展性:新增策略时,只需实现策略接口并创建新类,无需修改上下文代码。
总结
策略模式通过将不同算法或行为封装到独立的策略类中,实现了行为的动态切换和解耦。它适用于需要灵活选择算法或行为的场景,能有效减少条件语句并提高代码的可扩展性和维护性。在支付系统、算法选择和行为切换等场景中,策略模式是常见且高效的设计选择。