最近看到责任链模式的时候每增加一个处理类,就必须在责任链的实现类中手动增加到责任链中,具体代码基本就是list.add(new FilterImpl()),可以看到每次增加一个处理类,就必须添加一行上面的代码,不符合开闭原则(面向修改关闭,面向扩展开放)。于是想到了Java的SPI机制,可以实现插拔式组件,而Java自带的SPI机制是寻找借口的所有实现类,虽然一直被诟病,但是在本次的插拔式中,它却成了一个优点,因为我们需要把所有的实现类都放入处理器链中。

类图如下:

上代码,嘻嘻!

 1 package com.liekkas.spi.responsibility_chain_model;
2
3 import lombok.Data;
4
5 /**
6 * description 被处理的类
7 *
8 * @author liekkas 2020/12/02 23:33
9 */
10 @Data
11 public class Receipt {
12 public Receipt(String code,String message){
13 this.code = code;
14 this.message = message;
15 }
16 private String code;
17 private String message;
18 }
 1 package com.liekkas.spi.responsibility_chain_model;
2
3 /**
4 * description 处理器接口
5 *
6 * @author liekkas 2020/12/02 23:30
7 */
8 public interface Filter {
9
10 /**
11 * 处理方法
12 * @param receipt receipt
13 * @param filterChain filterChain
14 */
15 void handle(Receipt receipt,FilterChain filterChain);
16 }
 1 package com.liekkas.spi.responsibility_chain_model;
2
3 /**
4 * description 处理器链接口
5 *
6 * @author liekkas 2020/12/02 23:31
7 */
8 public interface FilterChain {
9
10 /**
11 * 处理方法
12 * @param receipt receipt
13 */
14 void handleReceipt(Receipt receipt);
15 }
 1 package com.liekkas.spi.responsibility_chain_model.impl;
2
3 import com.liekkas.spi.responsibility_chain_model.Filter;
4 import com.liekkas.spi.responsibility_chain_model.FilterChain;
5 import com.liekkas.spi.responsibility_chain_model.Receipt;
6
7 /**
8 * description 具体的处理器1
9 *
10 * @author liekkas 2020/12/02 23:35
11 */
12 public class FilterImpl1 implements Filter {
13
14 @Override
15 public void handle(Receipt receipt, FilterChain filterChain) {
16 if ("test001".equals(receipt.getCode())) {
17 System.out.println("我是Filter1,我能处理test001,已经处理" + receipt.getMessage());
18 }
19 //自己处理不了该回执就往下传递
20 else {
21 filterChain.handleReceipt(receipt);
22 }
23 }
24 }
 1 package com.liekkas.spi.responsibility_chain_model.impl;
2
3 import com.liekkas.spi.responsibility_chain_model.Filter;
4 import com.liekkas.spi.responsibility_chain_model.FilterChain;
5 import com.liekkas.spi.responsibility_chain_model.Receipt;
6
7 /**
8 * description 具体的处理器2
9 *
10 * @author liekkas 2020/12/02 23:35
11 */
12 public class FilterImpl2 implements Filter {
13
14 @Override
15 public void handle(Receipt receipt, FilterChain filterChain) {
16 if ("test002".equals(receipt.getCode())) {
17 System.out.println("我是Filter2,我能处理test002,已经处理" + receipt.getMessage());
18 }
19 //自己处理不了该回执就往下传递
20 else {
21 filterChain.handleReceipt(receipt);
22 }
23 }
24 }
 1 package com.liekkas.spi.responsibility_chain_model.impl;
2
3 import com.liekkas.spi.responsibility_chain_model.Filter;
4 import com.liekkas.spi.responsibility_chain_model.FilterChain;
5 import com.liekkas.spi.responsibility_chain_model.Receipt;
6
7 /**
8 * description 具体的处理器3
9 *
10 * @author liekkas 2020/12/02 23:35
11 */
12 public class FilterImpl3 implements Filter {
13
14 @Override
15 public void handle(Receipt receipt, FilterChain filterChain) {
16 if ("test003".equals(receipt.getCode())) {
17 System.out.println("我是Filter3,我能处理test003,已经处理" + receipt.getMessage());
18 }
19 //自己处理不了该回执就往下传递
20 else {
21 filterChain.handleReceipt(receipt);
22 }
23 }
24 }
 1 package com.liekkas.spi.responsibility_chain_model.impl;
2
3 import com.liekkas.spi.responsibility_chain_model.Filter;
4 import com.liekkas.spi.responsibility_chain_model.FilterChain;
5 import com.liekkas.spi.responsibility_chain_model.Receipt;
6 import com.liekkas.spi.responsibility_chain_model.container.ReceiptHandlerContainer;
7
8 import java.util.List;
9
10 /**
11 * description 处理器链默认的实现类
12 *
13 * @author liekkas 2020/12/02 23:38
14 */
15 public class DefaultFilterChainImpl implements FilterChain {
16
17 /**
18 * 记录当前处理者位置
19 */
20 private int index = 0;
21 /**
22 * 处理器集合
23 */
24 private static final List<Filter> FILTER_LIST;
25
26 static {
27 //从容器中获取处理器对象
28 FILTER_LIST = ReceiptHandlerContainer.getReceiptHandlerList();
29 }
30
31 @Override
32 public void handleReceipt(Receipt receipt) {
33 if (FILTER_LIST != null && FILTER_LIST.size() > 0) {
34 if (index < FILTER_LIST.size()) {
35 Filter filter = FILTER_LIST.get(index++);
36 filter.handle(receipt, this);
37 }
38 }
39 }
40 }
 1 package com.liekkas.spi.responsibility_chain_model.container;
2
3 import com.liekkas.spi.responsibility_chain_model.Filter;
4
5 import java.util.ArrayList;
6 import java.util.List;
7 import java.util.ServiceLoader;
8
9 /**
10 * description 装在过滤器的容器,采用SPI实现,当添加过滤器的时候只需按照SPI的格式要求,便可自动装载,
11 * 无需其他操作,即实现了插拔式,即插即用。
12 *
13 * @author liekkas 2020/12/02 23:43
14 */
15 public class ReceiptHandlerContainer {
16 private ReceiptHandlerContainer() {
17 }
18
19 public static List<Filter> getReceiptHandlerList() {
20 // SPI机制,寻找所有的实现类
21 ServiceLoader<Filter> filtersImplements = ServiceLoader.load(Filter.class);
22 List<Filter> receiptHandlerList = new ArrayList<>();
23 //把找到的所有的Filter的实现类放入List中
24 for (Filter filtersImplement : filtersImplements) {
25 receiptHandlerList.add(filtersImplement);
26 }
27 return receiptHandlerList;
28 }
29 }

最后在resources目录下建一个文件名为com.liekkas.spi.responsibility_chain_model.Filter的文件,文件名即是接口的全限定接口名,完整的目录如下:

src/main/resources/META-INF/services/com.liekkas.spi.responsibility_chain_model.Filter

文件内容为:

com.liekkas.spi.responsibility_chain_model.impl.FilterImpl1
com.liekkas.spi.responsibility_chain_model.impl.FilterImpl2
com.liekkas.spi.responsibility_chain_model.impl.FilterImpl3

下面我们就建一个客户端的测试类,来看一下效果,激动人心的时刻到了,嘿嘿嘿

package com.liekkas.spi.responsibility_chain_model;

import com.liekkas.spi.responsibility_chain_model.impl.DefaultFilterChainImpl;

import java.util.ArrayList;
import java.util.List; /**
* description 测试客户端
*
* @author liekkas 2020/12/02 23:52
*/
public class Client {
public static void main(String[] args) {
//模拟回执
List<Receipt> receiptList = ReceiptBuilder.generateReceiptList(); for (Receipt receipt : receiptList) {
//回执处理链对象
FilterChain receiptHandleChain = new DefaultFilterChainImpl();
receiptHandleChain.handleReceipt(receipt);
}
} static class ReceiptBuilder{
public static List<Receipt> generateReceiptList(){
List<Receipt> resultList = new ArrayList<>();
resultList.add(new Receipt("test001","测试消息one"));
resultList.add(new Receipt("test002","测试消息two"));
resultList.add(new Receipt("test003","测试消息three"));
return resultList;
}
}
}

执行的结果如下:

小结:通过本次的学习,不仅对责任链模式有了更深的理解也对SPI机制有了更深的理解,同时两者的结合实现了插拔式,也让我对软件的设计原则有了更深一步的认识!

利用SPI机制实现责任链模式中的处理类热插拔的更多相关文章

  1. 【设计模式】 模式PK:观察者模式VS责任链模式

    1.概述 为什么要把观察者模式和责任链模式放在一起对比呢?看起来这两个模式没有太多的相似性,真没有吗?回答是有.我们在观察者模式中也提到了触发链(也叫做观察者链)的问题,一个具体的角色既可以是观察者, ...

  2. 观察者模式 VS 责任链模式

    为什么要把观察者模式和责任链模式放在一起对比呢?这两个模式没有太多的相似性呀,真没有嘛?有相似性,我们在观察者模式中也提到了触发链(也叫做观察者链)的问题,一个具体的角色既可以是观察者,也可以是被观察 ...

  3. Netty中的责任链模式

    适用场景: 对于一个请求来说,如果有个对象都有机会处理它,而且不明确到底是哪个对象会处理请求时,我们可以考虑使用责任链模式实现它,让请求从链的头部往后移动,直到链上的一个节点成功处理了它为止 优点: ...

  4. Activiti工作流学习笔记(四)——工作流引擎中责任链模式的建立与应用原理

    原创/朱季谦 本文需要一定责任链模式的基础,主要分成三部分讲解: 一.简单理解责任链模式概念 二.Activiti工作流里责任链模式的建立 三.Activiti工作流里责任链模式的应用 一.简单理解责 ...

  5. 设计模式学习笔记(十四)责任链模式实现以及在Filter中的应用

    责任链模式(Chain Of Responsibility Design Pattern),也叫做职责链,是将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求.当有请求发生时,可将请求沿着这条 ...

  6. 责任链模式Scala的7种实现

    责任链模式是经典的GoF 23种设计模式之一,也许你已经了解这种模式.不管你是否熟悉,建议读者在阅读本文之前,不妨先思考下面三个问题: (1) 如何用多种风格迥异的编程范式来实现责任链模式? (2) ...

  7. 详解java设计模式之责任链模式

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt175 从击鼓传花谈起 击鼓传花是一种热闹而又紧张的饮酒游戏.在酒宴上宾客依次 ...

  8. 责任链模式 职责链模式 Chain of Responsibility Pattern 行为型 设计模式(十七)

    责任链模式(Chain of Responsibility Pattern) 职责链模式 意图 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系 将这些对象连接成一条链,并沿着这 ...

  9. Android事件分发与责任链模式

    一.责任链模式 责任链模式是一种行为模式,为请求创建一个接收者的对象链.这样就避免,一个请求链接多个接收者的情况.进行外部解耦.类似于单向链表结构. 优点: 1. 降低耦合度.它将请求的发送者和接收者 ...

随机推荐

  1. gitlab + php自动部署

    功能简介 本地往服务器推送代码之后,触发web钩子,服务器拉取刚刚推送的代码 步骤 1.在gitlab后台配置钩子 项目->编辑项目->Web钩子->新增钩子 2.在服务器端为www ...

  2. 2021/5/11 docker的应用

    很快一天过去了,今天虽然没有加班,但是依旧感觉疲惫,弄了一天的docker镜像的问题.作为一名前端开发工程师从以前从未听说过docker到现在懂得了如何运用,也是不容易啊.之前也说过,我们项目结构是前 ...

  3. CRM应用中可能发生的问题

    CRM系统是公认的提升企业竞争力的强大工具.它既是以客户为中心的思想,又是一种企业管理方案.当然,它还是一种管理软件.在国外,CRM使企业运营得风生水起,但在我国的企业应用中,还是有着很高的失败率和使 ...

  4. Arduino杀手在此!!ESP 8266 NodeMCU小白手把手入门(二)(解惑篇)

    上一次更新主要是简单介绍了NodeMCU的基本知识并且进行了一次简单的实操演示,最近有一些读者向我提出了一些小问题,所以决定出一期解惑篇,主要针对的是基础知识不是太牢固,或是喜欢刨根问底的小可爱们.里 ...

  5. [刷题] PTA 02-线性结构4 Pop Sequence

    模拟栈进出 方法一: 1 #include<stdio.h> 2 #define MAXSIZE 1000 3 4 typedef struct{ 5 int data[MAXSIZE]; ...

  6. 国内Ubuntu16.04下载地址<其他系统可返回最首项>

     ubuntu16.04下载地址: 中科大源       http://mirrors.ustc.edu.cn/ubuntu-releases/16.04/ 阿里云开源镜像站       http:/ ...

  7. Linux服务之Apache服务篇

    apache httpd:提供http服务 http超文本协议 HTML超文本标记语言 URL(Uniform Resource Locator)统一资源定位符 http://www.sina.com ...

  8. Scala 中为什么不建议用 return 关键字

    在scala中使用 return 的话,编译的时候会提示the latest statement is method is automatically returned, use of th retu ...

  9. 《Java架构师的最佳实践》生产环境JVM调优之空间担保失败引起的FullGC

    1  问题现象 应用prod-xxx-k8s,在内存足够的情况下,仍然会产生偶发FullGC的问题. JVM配置如下: -Xmx8192m -Dhsf.server.max.poolsize=2500 ...

  10. lua type 获取 类型

    lua中的类型作一小记 print(type("Hello world")) --> string print(type(10.4*3)) --> number pri ...