前言
策略模式是行为设计模式的一种,也是替代⼤量 ifelse 的利器。
1 策略模式的功能
策略模式的功能是把具体的算法实现,从具体的业务处理里面独立出来,实现成为单独的算法类(封装算法),从而形成一系列的算法,并让这些算法可以相互替换。策略模式的重心不是如何实现算法,而是如何组织和调用这些算法,从而让程序的结构更灵活,具有更好的维护性和扩展性。
1.1 实现一个计算器
以菜鸟教程中的计算器示例代码为例,使用if-else实现和策略模式两种实现方式进行对比。本文的代码均使用Java语言编写。
1.1.1 使用if-else实现
package dp.strategy.example4;
public class Calculator {
/**
* 根据输入的参数和运算符做加减乘除运算,最简单的计算器不考虑异常情况
* @param num1 输入运算数值1
* @param num2 输入运算数值2
* @param operation 预算符
* @return 返回结果
*/
public double doOperation(int num1, int num2, String operation) {
if ("+".equals(operation)) {
System.out.println(num1 + "+" + num2 + "=" + (num1 + num2));
return num1 + num2;
} else if ("-".equals(operation)) {
System.out.println(num1 + "-" + num2 + "=" + (num1 - num2));
return num1 - num2;
} else if ("*".equals(operation)) {
System.out.println(num1 + "*" + num2 + "=" + (num1 * num2));
return num1 * num2;
} else if ("/".equals(operation)) {
System.out.println(num1 + "/" + num2 + "=" + (num1 / num2));
return num1 / num2;
}
return 0;
}
}
1.1.2 使用策略模式实现
使用策略模式实现的代码会稍微复杂一些,将计算逻辑和调用计算的代码解耦了,其类图为:
源代码:
package dp.strategy.example5;
// 创建接口
public interface CalculatorStrategy {
public double doOperation(int num1, int num2);
}
// 创建实现接口的实现类,这里实现了加减乘三种运算
public class OperationAdd implements CalculatorStrategy{
@Override
public double doOperation(int num1, int num2) {
return num1 + num2;
}
}
public class OperationMultiply implements CalculatorStrategy{
@Override
public double doOperation(int num1, int num2) {
return num1 * num2;
}
}
public class OperationSubtract implements CalculatorStrategy{
@Override
public double doOperation(int num1, int num2) {
return num1 - num2;
}
}
// 创建上下文类用于调用具体的实现策略类
public class Context {
private CalculatorStrategy calculatorStrategy;
public Context(CalculatorStrategy strategy) {
this.calculatorStrategy = strategy;
}
public double executeStrategy(int num1, int num2) {
return calculatorStrategy.doOperation(num1, num2);
}
}
// 创建一个用户(调用方)类,调用不同的实现策略类
public class CalculatorClient {
public static void main(String[] args) {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationSubtract());
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationMultiply());
System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
}
}
2 策略模式和if-else写法的对比
如果在Client中直接使用if-else,或者将具体的实例化判断逻辑放在简单工厂方法中,都不是策略模式。一定要切记策略模式是一种行为型设计模式,其特点是:**通过抽象出策略接口,将具体的策略实现细节下放到了实现类当中,通过传参的形式将具体的策略传给Context,并将策略方法的调用封装在了Context中。**如此一来,便可以在Client(调用方)中根据对应应用场景向Context传入对应的实现类实例即可,基本就不再需要写if-else了。
当然也存在某些业务场景,仍然需要在Client中使用if-else判断生成哪个具体的实现类,在这种场景下我建议直接在Client中引入工厂模式进行重构,基本上能够消灭掉if-else了。
3 UML图
策略模式的类图如下:
对应plantUML图的代码:
@startuml
skinparam linetype ortho
package "Strategy" <<Frame>> {
interface Strategy {
+ method()
}
class ConcreteStrategyA {
+ method()
}
class ConcreteStrategyB {
+ method()
}
class ConcreteStrategyC {
+ method()
}
class ConcreteStrategyD {
+ method()
}
class Context {
- strategy
+ setStrategy(strategy)
+ execute()
}
note left of Context
// 在execute中调用具体策略实现类中的method()
execute() {
strategy.method()
}
end note
Strategy <|.. ConcreteStrategyA
Strategy <|.. ConcreteStrategyB
Strategy <|.. ConcreteStrategyC
Strategy <|.. ConcreteStrategyD
Context o--> Strategy
}
@enduml