策略模式(Strategy):定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。策略模式使得算法可独立于使用它的客户而变化。
适用场景:
1、许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法;
2、需要使用一个算法的不同变体;
3、算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构;
4、一个类定义了多种行为, 并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy 类中以代替这些条件语句。
通用类图:
实际上,策略模式是采用了面向对象的继承和多态机制,客户根据自己的业务需要调用上下文(Context 类)获得相应的具体策略、算法实现。
假设我们要实现一个非常简单的计算机,只能进行加减操作。一般我们会这样设计:根据传入的 String 型参数使用 if… else… 语句判断用户需要哪种操作。
代码如下:
- class Calculator {
- private final static String ADD = "+";
- private final static String SUB = "-";
- public int calculate(int a, int b, String operator) {
- int result = 0;
- if(this.ADD.equals(operator)) {
- result = a + b;
- }else {
- result = a - b;
- }
- return result;
- }
- }
- // 测试类
- public class Client {
- public static void main(String[] args) {
- Calculator calculator = new Calculator();
- System.out.println(calculator.calculate(10, 13, "+"));
- System.out.println(calculator.calculate(10, 13, "-"));
- }
- }
代码如下:
- // 定义算法框架,具体的算法由子类实现
- interface Operation {
- public int calculate(int a, int b);
- }
- class Add implements Operation {
- public int calculate(int a, int b) {
- return (a + b);
- }
- }
- class Sub implements Operation {
- public int calculate(int a, int b) {
- return (a - b);
- }
- }
- // 上下文 Context 类
- class Calculator {
- private Operation operation;
- // 设置具体的算法策略
- public void setOperation (Operation operation) {
- this.operation = operation;
- }
- public int calculate(int a, int b) {
- return this.operation.calculate(a, b);
- }
- }
- // 测试类
- public class Client {
- public static void main(String[] args) {
- Calculator calculator = new Calculator();
- // 加法操作
- calculator.setOperation(new Add());
- System.out.println(calculator.calculate(20, 13));
- // 减法操作
- calculator.setOperation(new Sub());
- System.out.println(calculator.calculate(20, 13));
- }
- }
如果此时我们需要添加乘除法,只需要再写一个实现了 Operation 接口的类,并实现其具体策略即可,在客户端即可方便地调用。
下面使用枚举策略的方式来实现,代码如下:
- // 策略枚举
- enum Calculator {
- // 加法策略的实现
- Add(){
- public int calculate(int a, int b) {
- return (a + b);
- }
- }, // 这里用逗号隔开各个枚举变量
- // 减法策略的实现
- Sub(){
- public int calculate(int a, int b) {
- return (a - b);
- }
- }; // 这里用逗号结束枚举变量的定义
- // 定义抽象算法方法,让每个枚举变量来具体实现
- public abstract int calculate(int a, int b);
- }
- public class Client {
- public static void main(String[] args) {
- // 加法
- System.out.println(Calculator.Add.calculate(20, 13));
- // 减法
- System.out.println(Calculator.Sub.calculate(20, 13));
- }
- }
使用枚举策略模式,不足是并不能像上面第二种方式那样适应变化,原因是如果要添加其他策略,同样需要修改枚举类,即添加具体的枚举变量。不过枚举策略的代码结构确实比较简洁。由于枚举策略的模式也不适合扩展,因此适合担任不会频繁发生变化的角色。
策略模式是比较简单的一个模式了,但是它也有不足之处:所有的具体策略都必须暴露给客户,否则客户怎样根据自身需要使用不同的策略呢?而且,策略模式实际上是把条件判断的逻辑(即各个条件分支,也就是每个具体策略)转移到客户端了,由客户来选择不同的具体策略。