策略模式(Strategy Pattern) 是一种行为型设计模式,它定义了一系列算法,将每种算法封装在独立的策略类中,使它们可以互换。策略模式允许在运行时选择不同的算法或操作,而无需修改使用它们的客户端代码。策略模式适用于有多种行为或算法可以互换的场景,能让代码更加灵活、扩展性更强。
1. 策略模式的结构
策略模式通常包括以下三个核心角色:
- 抽象策略(Strategy):定义一组算法的公共接口,通常是一个接口或抽象类,供具体策略实现。
- 具体策略(Concrete Strategy):实现抽象策略接口的多个具体类,每个类实现不同的算法或行为。
- 上下文(Context):持有一个策略接口的引用,可以动态设置或改变具体策略,负责与客户端代码交互,并在需要时调用策略接口定义的行为。
策略模式的 UML 类图
plaintextCopy code+------------------+ +----------------------+
| Context |<------->| Strategy |
+------------------+ +----------------------+
| strategy: Strategy | |+ algorithmInterface():void|
+------------------+ +----------------------+
|+ setStrategy(Strategy) | ^
|+ executeStrategy():void | |
+------------------+ +----------------------+
| |
| |
V V
+------------------+ +------------------+
| ConcreteStrategyA| | ConcreteStrategyB|
+------------------+ +------------------+
|+ algorithmInterface()| |+ algorithmInterface()|
+------------------+ +------------------+
2. 策略模式的实现
以下是策略模式的 Java 示例。假设我们要实现一个支付系统,支持不同的支付方式(如支付宝、微信、信用卡等),每种支付方式都有不同的实现逻辑。使用策略模式可以让我们根据需要选择不同的支付策略。
1. 定义策略接口
javaCopy codepublic interface PaymentStrategy {
void pay(double amount);
}
2. 实现具体策略
支付宝支付策略
javaCopy codepublic class AlipayStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付 " + amount + " 元");
}
}
微信支付策略
javaCopy codepublic class WeChatPayStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("使用微信支付 " + amount + " 元");
}
}
信用卡支付策略
javaCopy codepublic class CreditCardStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("使用信用卡支付 " + amount + " 元");
}
}
3. 创建上下文类
上下文类持有一个策略接口的引用,负责根据不同的策略执行支付操作:
javaCopy codepublic class PaymentContext {
private PaymentStrategy paymentStrategy;
// 设置支付策略
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
// 执行支付操作
public void executePayment(double amount) {
if (paymentStrategy == null) {
throw new IllegalStateException("支付策略未设置");
}
paymentStrategy.pay(amount);
}
}
4. 客户端代码
在客户端代码中,我们可以根据需要选择不同的支付策略并执行支付:
javaCopy codepublic class Client {
public static void main(String[] args) {
PaymentContext context = new PaymentContext();
// 使用支付宝支付
context.setPaymentStrategy(new AlipayStrategy());
context.executePayment(100);
// 使用微信支付
context.setPaymentStrategy(new WeChatPayStrategy());
context.executePayment(200);
// 使用信用卡支付
context.setPaymentStrategy(new CreditCardStrategy());
context.executePayment(300);
}
}
输出结果:
plaintextCopy code使用支付宝支付 100 元
使用微信支付 200 元
使用信用卡支付 300 元
3. 策略模式的优缺点
优点
- 扩展性强:添加新策略时,无需修改现有代码,只需新增策略类,符合开闭原则(Open/Closed Principle)。
- 避免条件判断:通过将不同的行为封装在独立策略中,消除了在上下文中对条件语句的依赖,代码更加简洁。
- 灵活性高:在运行时可以动态切换策略,使代码更加灵活。
缺点
- 增加类数量:每个策略都需要创建一个新的类,类的数量可能较多。
- 客户端必须了解策略:客户端需要知道有哪些策略类,并且要知道何时使用哪种策略。
- 不适合策略过多的场景:如果策略数量过多,可能导致类文件增多,不便于维护。
4. 策略模式的使用场景
策略模式适用于以下场景:
- 多种算法或行为可以互换:如支付方式、数据排序方式、不同折扣计算方式等。
- 消除大量条件分支:当算法或行为有多个实现且通过条件语句选择时,可以使用策略模式替代条件语句。
- 动态行为控制:在运行时需要动态切换行为,比如不同的促销策略等。
5. 策略模式的扩展与优化
1. 使用工厂模式创建策略对象
当策略的选择由特定条件决定时,可以将策略选择逻辑封装在工厂类中,通过工厂模式动态创建策略对象,避免在客户端代码中频繁创建具体策略实例。
javaCopy codepublic class PaymentStrategyFactory {
public static PaymentStrategy getStrategy(String type) {
switch (type) {
case "Alipay":
return new AlipayStrategy();
case "WeChat":
return new WeChatPayStrategy();
case "CreditCard":
return new CreditCardStrategy();
default:
throw new IllegalArgumentException("未知的支付方式");
}
}
}
2. 使用注解和反射动态加载策略
在 Spring 中,可以通过注解、反射或依赖注入(DI)实现策略的自动管理,减少代码中的硬编码。例如,可以将策略类用 @Component
注解标记,然后通过 Spring 容器管理,自动注入到上下文中。
3. 优化策略的选择逻辑
如果策略种类非常多,且经常需要根据复杂条件选择策略,可以使用 策略模式结合状态模式,在不同状态下动态选择合适的策略。
6. 总结
- 策略模式通过定义一系列可以互换的算法,使客户端代码在运行时动态选择不同的策略。
- 优势:代码解耦、扩展性强,避免大量条件判断。
- 劣势:类文件增多,可能会让代码难以管理。
- 适用场景:多种算法、行为互换,或需要根据条件动态选择算法的场景。
策略模式使得不同算法或行为独立封装,实现了代码的高扩展性和灵活性。