目录

策略模式

Strategy

定义

Define a family of algorithms, encapsulate each one, and make them interchangeable. The Strategy pattern lets the algorithm vary independently from clients that use it. 策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而变化。

OO设计原则——封装变化对接口编程而不是对实现编程

在策略模式中它将这些解决问题的方法定义成一个算法群,每一个方法都对应着一个具体的算法,这里的一个算法我就称之为一个策略。虽然策略模式定义了算法,但是它并不提供算法的选择,即什么算法对于什么问题最合适这是策略模式所不关心的,所以对于策略的选择还是要客户端来做。客户必须要清楚的知道每个算法之间的区别和在什么时候什么地方使用什么策略是最合适的,这样就增加客户端的负担。

​ 同时策略模式也非常完美的符合了“开闭原则”,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。但是一个策略对应一个类将会是系统产生很多的策略类。

参与者:

  • Context: 环境类。维护一个Strategy对象的引用,用一个ConcreteStrategy来配置,可定义一个接口来让Strategy访问它的数据。
  • Strategy: 抽象策略类。定义所有支持算法的公共接口。Context使用这个接口来调用某个Concretestrategy定义的算法。
  • ConcreteStrategy: 具体策略类。封装了具体的算法实现。

实现

Strategy

1
2
3
public interface Strategy {
   public int doOperation(int num1, int num2);
}

实现接口

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class OperationAdd implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 + num2;
   }
}
public class OperationSubstract implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 - num2;
   }
}

创建 Context

1
2
3
4
5
6
7
8
9
public class Context {
   private Strategy strategy;
   public Context(Strategy strategy){
      this.strategy = strategy;
   }
   public int executeStrategy(int num1, int num2){
      return strategy.doOperation(num1, num2);
   }
}

测试 策略改变Context的行为变化

1
2
3
4
5
6
7
8
public class StrategyPatternDemo {
   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 OperationSubstract());
      System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
   }
}

在 Context 中通过类型映射策略:

  • 维护了一个类型对应策略的 Map 容器。用这种方式就需要判断每种策略是否可以共享使用。
  • 每次根据类型 new 一个新的策略类对象(工厂方法)。这个就需要根据实际业务场景去做的判断。

Map 的 value 的策略接口的实现,如果策略比较简单,可以使用 JDK 提供的函数式接口。 如果在 Spring Boot 定义策略实现接口时加 @Component,框架自动帮你将其注入到 Map 中。

应用

JDK 中的线程池 ThreadPoolExecutor,线程池的异常策略就是用的策略模式的思想。RejectedExecutionHandler这个抽象异常策略接口,同时它也有四种拒绝策略。