一、策略模式

概述

在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式

在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法

主要解决:在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护

何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为

策略模式一般用于各种算法上面

优缺点

优点:

1、算法可以自由切换

2、避免使用多重条件判断

3、扩展性良好

缺点:

1、策略类会增多

2、所有策略类都需要对外暴露

1. 各个角色介绍

1.1 策略类(Strategy

策略是一个接口,该接口定义若干个操作标识,即定义了若干个方法

1.2 环境类 / 策略上下文类(Context)

上下文是依赖于接口的类(是面向策略设计的类,如下图 Context 类),即上下文包含用策略(接口)声明的变量(如下图的strategy成员变量)

上下文提供一个方法(如下图Context类中的的 executeStrategy() 方法),持有一个策略类的引用,最终给客户端调用。该方法委托策略变量调用具体策略所实现的策略接口中的方法(实现接口的类重写策略中的方法,来完成具体功能)

1.3 具体策略类(ConcreteStrategy)

具体策略是实现策略接口的类(如下图的ConcreteStrategyA类和ConcreteStrategyB类)。具体策略实现策略接口所定义的方法,即给出操作标识的具体方法

2. UML图

3. 具体例子和代码

角色分配

  • Strategy:策略接口
  • OperationAdd:加法策略(实现策略接口)
  • OperationSubtract:减法策略(实现策略接口)
  • OperationMultiply:乘法策略(实现策略接口)
  • OperationDivision:除法策略(实现策略接口)
  • Context:策略上下文

3.1 策略接口以及实现类

  • Strategy
package com.vinjcent.pattern.strategy;/** * @author vinjcent * @description 策略接口 */public interface Strategy {/** * 实现该接口的方法 * @param num1数值1 * @param num2数值2 * @return计算结果 */int doOperation(int num1, int num2);}
  • OperationAdd
package com.vinjcent.pattern.strategy;/** * @author vinjcent * @description 加法策略 */public class OperationAdd implements Strategy {@Overridepublic int doOperation(int num1, int num2) {return num1 + num2;}}
  • OperationSubtract
package com.vinjcent.pattern.strategy;/** * @author vinjcent * @description 减法策略 */public class OperationSubtract implements Strategy {@Overridepublic int doOperation(int num1, int num2) {return num1 - num2;}}
  • OperationMultiply
package com.vinjcent.pattern.strategy;/** * @author vinjcent * @description 乘法策略 */public class OperationMultiply implements Strategy {@Overridepublic int doOperation(int num1, int num2) {return num1 * num2;}}
  • OperationDivision
package com.vinjcent.pattern.strategy;/** * @author vinjcent * @description 除法策略 */public class OperationDivision implements Strategy {@Overridepublic int doOperation(int num1, int num2) {return num1 / num2;}}

3.2 策略上下文类

  • Context
package com.vinjcent.pattern.strategy;/** * @author vinjcent * @description 策略上下文 */public class Context {private Strategy strategy;public Context(Strategy strategy) {this.strategy = strategy;}public Strategy getStrategy() {return strategy;}public void setStrategy(Strategy strategy) {this.strategy = strategy;}public int executeStrategy(int num1, int num2) {return strategy.doOperation(num1, num2);}}

3.3 测试主函数

package com.vinjcent.pattern.strategy;/** * @author vinjcent */public class Main {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));// 除法策略context = new Context(new OperationDivision());System.out.println("10 * 5 = " + context.executeStrategy(10, 5));}}
  • 测试结果

4. 使用场景

  • 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为
  • 一个系统需要动态地在几种算法中选择一种
  • 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现

注意事项:

如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题