策略模式(Strategy Pattern)
概念
策略模式(Strategy Pattern)是一种行为型设计模式,允许定义一系列算法,将每个算法封装在策略类中,并使它们可以互换使用。客户端可以根据需要动态选择不同的策略对象,从而在运行时决定采用哪种具体算法。
应用场景
-
算法的可替换性:当系统有多个不同的算法且这些算法可以互相替换时,可以使用策略模式。例如,排序算法、压缩算法等不同算法的实现。
-
避免条件分支 :当系统中存在大量的
if-else
或switch-case
语句以选择不同的算法或行为时,可以使用策略模式将这些条件分支移入不同的策略类中,减少代码复杂度。 -
动态地选择行为:策略模式允许在运行时动态地选择或切换不同的算法或行为。例如,支付系统中可以选择不同的支付方式(如信用卡、支付宝、微信等)作为策略。
-
解耦行为与使用者:策略模式使得具体的算法实现与使用算法的类解耦,使用者无需了解具体的算法实现,只需使用策略接口即可。
注意点
- 策略的数量:随着算法或行为的增加,策略类的数量也会增加,可能会造成类数量的膨胀。
- 策略的独立性:策略类应当是独立的,相互之间不应依赖。如果策略之间有逻辑关系,可能需要进一步重构。
- 客户端必须知晓策略:客户端需要了解并决定使用哪种策略,可能增加其复杂度。
核心要素
- Strategy(策略接口):定义一系列可供选择的算法或行为。
- ConcreteStrategy(具体策略):具体的算法实现类,每个策略类实现不同的算法。
- Context(上下文类):维护一个策略对象,并根据客户端的选择动态使用不同的策略。
Java代码完整示例
代码示例:简单策略模式
java
// 定义策略接口
interface Strategy {
void execute();
}
// 具体策略类 A
class ConcreteStrategyA implements Strategy {
@Override
public void execute() {
System.out.println("使用策略A进行操作");
}
}
// 具体策略类 B
class ConcreteStrategyB implements Strategy {
@Override
public void execute() {
System.out.println("使用策略B进行操作");
}
}
// 上下文类,维护一个策略对象
class Context {
private Strategy strategy;
// 构造函数注入策略对象
public Context(Strategy strategy) {
this.strategy = strategy;
}
// 动态设置策略
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
// 执行策略
public void executeStrategy() {
strategy.execute();
}
}
// 客户端代码
public class StrategyPatternDemo {
public static void main(String[] args) {
// 使用策略A
Context context = new Context(new ConcreteStrategyA());
context.executeStrategy();
// 切换到策略B
context.setStrategy(new ConcreteStrategyB());
context.executeStrategy();
}
}
输出结果:
使用策略A进行操作
使用策略B进行操作
各种变形用法完整示例
-
策略模式结合枚举
通过枚举来实现策略模式,每个枚举实例代表一种策略。
代码示例:
javaenum PaymentStrategy { CREDIT_CARD { @Override public void pay(double amount) { System.out.println("使用信用卡支付: " + amount + " 元"); } }, PAYPAL { @Override public void pay(double amount) { System.out.println("使用PayPal支付: " + amount + " 元"); } }, ALIPAY { @Override public void pay(double amount) { System.out.println("使用支付宝支付: " + amount + " 元"); } }; public abstract void pay(double amount); } public class PaymentContext { private PaymentStrategy strategy; public PaymentContext(PaymentStrategy strategy) { this.strategy = strategy; } public void setStrategy(PaymentStrategy strategy) { this.strategy = strategy; } public void pay(double amount) { strategy.pay(amount); } public static void main(String[] args) { PaymentContext context = new PaymentContext(PaymentStrategy.CREDIT_CARD); context.pay(100.0); context.setStrategy(PaymentStrategy.PAYPAL); context.pay(200.0); context.setStrategy(PaymentStrategy.ALIPAY); context.pay(300.0); } }
输出结果:
使用信用卡支付: 100.0 元 使用PayPal支付: 200.0 元 使用支付宝支付: 300.0 元
-
策略模式结合Lambda表达式
在Java 8中,可以使用Lambda表达式简化策略模式的实现,将策略作为函数式接口来处理。
代码示例:
javainterface Strategy { void execute(); } public class StrategyLambdaDemo { public static void main(String[] args) { // 使用Lambda表达式定义不同策略 Strategy strategyA = () -> System.out.println("使用策略A执行操作"); Strategy strategyB = () -> System.out.println("使用策略B执行操作"); // 创建上下文并设置策略 Context context = new Context(strategyA); context.executeStrategy(); context.setStrategy(strategyB); context.executeStrategy(); } }
输出结果:
使用策略A执行操作 使用策略B执行操作
-
策略模式结合工厂模式
可以通过工厂模式来创建不同的策略对象,并根据条件动态选择合适的策略。
代码示例:
java// 定义策略接口 interface Strategy { void execute(); } // 具体策略类 A class ConcreteStrategyA implements Strategy { @Override public void execute() { System.out.println("使用策略A进行操作"); } } // 具体策略类 B class ConcreteStrategyB implements Strategy { @Override public void execute() { System.out.println("使用策略B进行操作"); } } // 策略工厂类 class StrategyFactory { public static Strategy getStrategy(String type) { switch (type) { case "A": return new ConcreteStrategyA(); case "B": return new ConcreteStrategyB(); default: throw new IllegalArgumentException("未知策略类型"); } } } // 上下文类 class Context { private Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } public void executeStrategy() { strategy.execute(); } } // 客户端 public class StrategyFactoryDemo { public static void main(String[] args) { // 通过工厂创建策略对象 Context context = new Context(StrategyFactory.getStrategy("A")); context.executeStrategy(); context = new Context(StrategyFactory.getStrategy("B")); context.executeStrategy(); } }
输出结果:
使用策略A进行操作 使用策略B进行操作
-
策略模式结合依赖注入
使用依赖注入框架(如Spring)动态选择策略,这样可以将策略的选择交给框架来管理。
代码示例(伪代码):
java// 定义策略接口 interface Strategy { void execute(); } // 具体策略类 A @Component("strategyA") class ConcreteStrategyA implements Strategy { @Override public void execute() { System.out.println("使用策略A进行操作"); } } // 具体策略类 B @Component("strategyB") class ConcreteStrategyB implements Strategy { @Override public void execute() { System.out.println("使用策略B进行操作"); } } // 上下文类 @Component class Context { private final Map<String, Strategy> strategies; // 使用Spring自动注入策略Map public Context(Map<String, Strategy> strategies) { this.strategies = strategies; } public void executeStrategy(String strategyType) { Strategy strategy = strategies.get(strategyType); if (strategy != null) { strategy.execute(); } else { throw new IllegalArgumentException("未知策略类型"); } } } // 客户端 @SpringBootApplication public class StrategySpringDemo { public static void main(String[] args) { ApplicationContext context = SpringApplication.run(StrategySpringDemo.class, args); Context strategyContext = context.getBean(Context.class); strategyContext.executeStrategy("strategyA"); strategyContext.executeStrategy("strategyB"); } }
输出结果:
使用策略A进行操作 使用策略B进行操作
通过这些不同的变形,策略模式不仅能应对多种不同的需求场景,还能与现代开发方法(如枚举、Lambda、工厂模式、依赖注入等)灵活结合,进一步提升代码的可维护性和可扩展性。