利用SPI机制实现责任链模式中的处理类热插拔
最近看到责任链模式的时候每增加一个处理类,就必须在责任链的实现类中手动增加到责任链中,具体代码基本就是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机制实现责任链模式中的处理类热插拔的更多相关文章
- 【设计模式】 模式PK:观察者模式VS责任链模式
1.概述 为什么要把观察者模式和责任链模式放在一起对比呢?看起来这两个模式没有太多的相似性,真没有吗?回答是有.我们在观察者模式中也提到了触发链(也叫做观察者链)的问题,一个具体的角色既可以是观察者, ...
- 观察者模式 VS 责任链模式
为什么要把观察者模式和责任链模式放在一起对比呢?这两个模式没有太多的相似性呀,真没有嘛?有相似性,我们在观察者模式中也提到了触发链(也叫做观察者链)的问题,一个具体的角色既可以是观察者,也可以是被观察 ...
- Netty中的责任链模式
适用场景: 对于一个请求来说,如果有个对象都有机会处理它,而且不明确到底是哪个对象会处理请求时,我们可以考虑使用责任链模式实现它,让请求从链的头部往后移动,直到链上的一个节点成功处理了它为止 优点: ...
- Activiti工作流学习笔记(四)——工作流引擎中责任链模式的建立与应用原理
原创/朱季谦 本文需要一定责任链模式的基础,主要分成三部分讲解: 一.简单理解责任链模式概念 二.Activiti工作流里责任链模式的建立 三.Activiti工作流里责任链模式的应用 一.简单理解责 ...
- 设计模式学习笔记(十四)责任链模式实现以及在Filter中的应用
责任链模式(Chain Of Responsibility Design Pattern),也叫做职责链,是将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求.当有请求发生时,可将请求沿着这条 ...
- 责任链模式Scala的7种实现
责任链模式是经典的GoF 23种设计模式之一,也许你已经了解这种模式.不管你是否熟悉,建议读者在阅读本文之前,不妨先思考下面三个问题: (1) 如何用多种风格迥异的编程范式来实现责任链模式? (2) ...
- 详解java设计模式之责任链模式
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt175 从击鼓传花谈起 击鼓传花是一种热闹而又紧张的饮酒游戏.在酒宴上宾客依次 ...
- 责任链模式 职责链模式 Chain of Responsibility Pattern 行为型 设计模式(十七)
责任链模式(Chain of Responsibility Pattern) 职责链模式 意图 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系 将这些对象连接成一条链,并沿着这 ...
- Android事件分发与责任链模式
一.责任链模式 责任链模式是一种行为模式,为请求创建一个接收者的对象链.这样就避免,一个请求链接多个接收者的情况.进行外部解耦.类似于单向链表结构. 优点: 1. 降低耦合度.它将请求的发送者和接收者 ...
随机推荐
- PhpStorm个性化设置推荐
预览 字体 字体使用jetbrains的mono,前往下载:如何安装,字体安装完成之后Restart,可在PhpStorm settings中搜索 font 进行启用 mono 字体 主题 主题推荐使 ...
- thinkphp 中区块block和模板继承extend用法举例
1.介绍 模板继承其实并不难理解,就好比类的继承一样,模板也可以定义一个基础模板(或者是布局),并且其中定义相关的区块(block),然后继承(extend)该基础模板的子模板中就可以对基础模板中定义 ...
- MySQL 连接超时:报错SQLSTATE[HY000] [2002] Connection timed out解决
当你的代码部署到服务器里的时候,你的mysql 的host 值 应该为 127.0.0.1 而不是 你的服务器ip 不然就会报错. 其实当你的代码进入到服务器里的时候,mysql和代码是相当于在同一个 ...
- Outlook关闭时最小化
一:背景环境: 当使用Outlook的时候,不小心点关闭,会不能及时发现接收的新邮件. 二:解决方法: 利用KeepOutlookRunning.dll插件,可以实现,点击关闭时,outlook没有实 ...
- 使用DevExpress的GridControl实现多层级或无穷级的嵌套列表展示
在我早期的随笔<在GridControl表格控件中实现多层级主从表数据的展示>中介绍过GridControl实现二级.三级的层级列表展示,主要的逻辑就是构建GridLevelNode并添加 ...
- 改善c++程序的150个建议(读后总结)-------10-11
10. 优化结构体中元素的布局 结构体变量所占空间大小并不是其所含类型所占字节数之和,其所占内存字节数涉及到字节对齐. 字节对齐 :变量在内存中储存都是以字节数为单位,每一个字节都有自己的地址,逻辑上 ...
- 免费JS甘特图组件dhtmlxgantt
安装 参考:https://docs.dhtmlx.com/gantt/desktop__install_with_bower.html 可使用NuGet.Bower.npm包管理器安装(应用在asp ...
- BugkuCTF——wp(旧版)
title: BugkuCTF--wp(旧版) date: 2020-4-25 tags: CTF,比赛 categories: CTF 比赛 Web篇 0x001-web2 解题思路: 1.直接按F ...
- window 共享打印机
https://www.zhihu.com/question/20653708 https://h30471.www3.hp.com/t5/da-yin-ji-yu-sao-miao-yi-de-an ...
- zabbix学习笔记:zabbix监控之短信报警
zabbix学习笔记:zabbix监控之短信报警 zabbix的报警方式有多种,除了常见的邮件报警外,特殊情况下还需要设置短信报警和微信报警等额外方式.本篇文章向大家介绍短信报警. 短信报警设置 短信 ...