设计模式之策略模式

一、策略模式概述

  策略模式(Strategy):定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的调用者。

二、策略模式解析

  策略模式是一种定义一系列算法的方法,从概念上看,所有的算法完成的都是相同的工作,只是实现不同,策略模式可以用相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。

  策略模式的Strategy类层次结构为Context(上下文)定义了一系列可供重用的算法或行为,继承有助于析取出这些算法的公共功能。

三、策略模式UML类图

 

四、代码示例

  没有代码的陪衬就好像在耍流氓,下面来看策略模式的代码示例。

场景:

  就拿去公司上班的场景为例,我们上班必须要去公司,这个目的地是固定的。员工怎么去到公司呢,根据实际场景,住的离公司近的同事,可以选择步行或者骑车,住的远的可能会选择自驾,出行的方式由员工而定。下面我们用代码来实现这一场景。

4.1、将出行方式抽象

复制代码
1 /**
2  *     出行至公司的方式
3  */
4 public interface ITripMode {
5     
6     public String tripWay();
7     
8 }
View Code
复制代码

4.2、出行方式选择步行

复制代码
1 public class WalkStrategy implements ITripMode {
2     @Override
3     public String tripWay() {
4         return "步行至公司";
5     }
6 }
View Code
复制代码

4.3、出行方式选择自驾

复制代码
1 public class CarTripStrategy implements ITripMode {
2     @Override
3     public String tripWay() {
4         return "自驾至公司";
5     }
6 }
View Code
复制代码

4.4、出行方式选择骑行

复制代码
1 public class BikeStrategy implements ITripMode {
2     @Override
3     public String tripWay() {
4         return "骑行至公司";
5     }
6 }
View Code
复制代码

4.5、持有出行方式(算法)的上下文

复制代码
 1 public class TripModeContext {
 2 
 3     private ITripMode mode;
 4 
 5     public TripModeContext(ITripMode mode) {
 6         this.mode = mode;
 7     }
 8     
 9     public String tripWay() {
10         return mode.tripWay();
11     }
12     
13 }
View Code
复制代码

4.6、测试

复制代码
1 public class StrategyTest {
2     public static void main(String[] args) {
3         ITripMode mode = new CarTripStrategy();
4         TripModeContext context = new TripModeContext(mode);
5         System.out.println("选择的出行方式是:" + context.tripWay());
6     }
7 }
View Code
复制代码

  运行结果如下:

  ITripMode定义了算法的公共接口;BikeStrategy、WalkStrategy、CarStrategy作为具体的算法实现;TripModeContext作为上下文,持有ITripMode的引用,作为算法处理的入口,由此可见,策略模式将具体的算法实现与调用算法的客户端做了解耦,当员工有其他的出行方式时,创建一个类实现ITripMode,不必修改现有代码逻辑,使得系统更容易维护。

五、策略模式在JDK中的应用

线程池中的拒绝策略采用了策略模式,分析如下:

5.1、我们先来看拒绝策略的老大哥RejectedExecutionHandler,老大哥规定了拒绝的算法。

1 public interface RejectedExecutionHandler {
2     void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
3 }
View Code

5.2、abort小弟实现RejectedExecutionHandler的方式

复制代码
1 //ThreadPoolExecutor中的静态内部类
2 public static class AbortPolicy implements RejectedExecutionHandler {
3         public AbortPolicy() { }
4         public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
5             throw new RejectedExecutionException("Task " + r.toString() +
6                                                  " rejected from " +
7                                                  e.toString());
8         }
9     }
View Code
复制代码

  abort小弟实现的拒绝策略:一旦指定拒绝策略为AbortPolicy ,任务数量使线程池饱和时,会抛出异常。

5.3、discardOldest小弟实现RejectedExecutionHandler的方式

复制代码
1 public static class DiscardOldestPolicy implements RejectedExecutionHandler {
2         public DiscardOldestPolicy() { }
3         public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
4             if (!e.isShutdown()) {
5                 e.getQueue().poll();
6                 e.execute(r);
7             }
8         }
9     }
View Code
复制代码

  discardOldest小弟实现的拒绝策略:当e.getQueue()获取线程的工作队列,因为队列遵循(FIFO)先进先出,所以当任务数量使线程池饱和时,线程池e.getQueue().poll()将队列头的数据移除,即移除工作队列中最老的任务,执行新的任务。

5.4、discard小弟实现RejectedExecutionHandler的方式

复制代码
1 public static class DiscardPolicy implements RejectedExecutionHandler {
2         public DiscardPolicy() { }
3         public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
4         }
5     }
View Code 
复制代码

  discard小弟实现的拒绝策略:这个小弟最懒,什么都不做,直接把任务丢弃了。

5.5、CallerRuns小弟实现RejectedExecutionHandler的方式

复制代码
1 public static class CallerRunsPolicy implements RejectedExecutionHandler {
2         public CallerRunsPolicy() { }
3         public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
4             if (!e.isShutdown()) {
5                 r.run();
6             }
7         }
8     }
View Code  
复制代码

  CallerRunsPolicy 小弟实现的拒绝策略:只要线程池没有关闭的话,则使用调用线程直接运行任务。

5.6、我们再来看看RejectedExecutionHandler 的上下文Context---ThreadPoolExecutor,主要代码如下:

复制代码
 1 public class ThreadPoolExecutor extends AbstractExecutorService {
 2 ......
 3 
 4        /**
 5      * Handler called when saturated or shutdown in execute.
 6      */
 7      // 只有工作队列饱和或者线程关闭时调用拒绝的处理
 8 private volatile RejectedExecutionHandler handler;
 9 
10 ......
11 
12       /**
13      * The default rejected execution handler
14      */
15      // 线程池默认的拒绝策略
16 private static final RejectedExecutionHandler defaultHandler =  new AbortPolicy();  
17 
18 ......
19 
20  // ThreadPoolExecutor的构造函数,当不指定拒绝策略时,
21 //会调用默认的拒绝策略
22 public ThreadPoolExecutor(int corePoolSize,
23                               int maximumPoolSize,
24                               long keepAliveTime,
25                               TimeUnit unit,
26                               BlockingQueue<Runnable> workQueue) {
27         this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
28              Executors.defaultThreadFactory(), defaultHandler);
29     }
30 
31 ......
32 
33 // ThreadPoolExecutor的构造函数,根据业务场景指定拒绝策略,
34 // 也可自定义拒绝策略
35 public ThreadPoolExecutor(int corePoolSize,
36                               int maximumPoolSize,
37                               long keepAliveTime,
38                               TimeUnit unit,
39                               BlockingQueue<Runnable> workQueue,
40                               ThreadFactory threadFactory,
41                               RejectedExecutionHandler handler) {
42         if (corePoolSize < 0 ||
43             maximumPoolSize <= 0 ||
44             maximumPoolSize < corePoolSize ||
45             keepAliveTime < 0)
46             throw new IllegalArgumentException();
47         if (workQueue == null || threadFactory == null || handler == null)
48             throw new NullPointerException();
49         this.acc = System.getSecurityManager() == null ?
50                 null :
51                 AccessController.getContext();
52         this.corePoolSize = corePoolSize;
53         this.maximumPoolSize = maximumPoolSize;
54         this.workQueue = workQueue;
55         this.keepAliveTime = unit.toNanos(keepAliveTime);
56         this.threadFactory = threadFactory;
57         this.handler = handler;
58     }
59 
60 ......
61 
62 // 拒绝策略处理
63 final void reject(Runnable command) {
64         handler.rejectedExecution(command, this);
65  }
66 
67 }
View Code
复制代码

由上面的分析,我们可以做一下对比,

  RejectedExecutionHandler作为策略模式中Strategy的存在,是对拒绝策略算法的抽象。

  ThreadPoolExecutor 是作为策略模式中上下文的存在,客户端调用拒绝策略的入口。

本文部分内容摘自《大话设计模式》。

posted @   无虑的小猪  阅读(232)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示