参考:https://www.jianshu.com/p/3bcf55cf83d3
策略模式也叫政策模式。指的是对象具备某种行为,但是在不同的场景中,该行为有不同的实现。
策略模式使用的就是面向对象的继承和多态的机制,从而实现同一行为在不同场景下具备不同的实现。
策略模式本质:分离算法、选择实现。
策略模式主要解决在有很多种算法相似的情况下,比如if…else或者switch…case比较多,使系统看起来比较复杂臃肿,就可以考虑通过策略模式才进行优化。遵守开闭原则 ,对修改是封闭的,扩展是开放的。从而使系统易于扩展和维护。
从UML类图中,可以看出它包含三种角色:
上下文角色(Context) :用来操作策略的上下文环境,屏蔽高层模块(客户端)对策略,算法的直接访问,封装可能存在的变化;
抽象策略角色(Strategy) :规定策略或算法的行为;
具体策略角色(ConcreteStrategy) :具体的策略或算法实现;
假如现在有一个需求,计算两个数,要求使用运算符+、-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Calculator { private static final String ADD = "+" ; private static final String SUB = "-" ; public static int calc (int a,int b,final String symbol) { int result = 0 ; if (ADD.equals(symbol)){ result = a + b; } else if (SUB.equals(symbol)) { result = a - b; } return result; } }
这是直接通过判断符号来对这两个数进行运算,如果我又有新的需求,需要*和/,那么就要在calc方法内去新增if…else判断,代码会随着需求越来越臃肿,而且这样扩展性很低。
采用策略模式后,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 public interface CalculatorStrategy { int calc (int a,int b) ; } public class AddCalculator implements CalculatorStrategy { @Override public int calc (int a, int b) { return a+b; } } public class SubCalculator implements CalculatorStrategy { @Override public int calc (int a, int b) { return a-b; } } public class MultiCalculator implements CalculatorStrategy { @Override public int calc (int a, int b) { return a*b; } } public class DivideCalculator implements CalculatorStrategy { @Override public int calc (int a, int b) { return a/b; } } public class Context { private CalculatorStrategy calculatorStrategy; public Context () {} public Context (CalculatorStrategy calculatorStrategy) { this .calculatorStrategy = calculatorStrategy; } public int calc (int a,int b) { return this .calculatorStrategy.calc(a,b); } } public class Main { public static void main (String[] args) { CalculatorStrategy calculatorStrategy = new MultiCalculator (); Context context = new Context (calculatorStrategy); int result = context.calc(10 , 5 ); System.out.println(result); } }
这样我们就可以消除对运算符判断的冗余,取而代之的是客户端来决定使用哪种策略,然后交给上下文去获取结果,后续如果有新的运算只需扩展相应的策略类而已。
注意 :策略模式 中的上下文环境(Context),其职责本来是隔离客户端与策略类的耦合,让客户端完全与上下文环境沟通,无需关系具体策略。但是从上面的代码中我们可以看到,客户端内部直接自己指定要哪种策略(CalculatorStrategy calculatorStrategy= new MultiCalculator()
),客户端与具体策略类耦合了,而上下文环境在这里其的作用只是负责调度执行,获取结果,并没有完全起到隔离客户端与策略类的作用。一般可以通过简单工厂模式将具体策略的创建与客户端进行隔离,或者是通过 策略枚举 将上下文环境与具体策略类融合在一起,简化代码。当具体策略相对稳定时,推荐使用 **策略枚举 **简化代码,具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class EnumClient { public static void main (String[] args) { int result = Calculator.ADD.calc(1 , 2 ); System.out.println(result); } static enum Calculator { ADD("+" ) { @Override public int calc (int a, int b) { return a + b; } }, SUB("-" ) { @Override public int calc (int a, int b) { return a - b; } }; private String symbol; private Calculator (String symbol) { this .symbol = symbol; } public String getSymbol () { return this .symbol; } public abstract int calc (int a, int b) ; } }