最近看到责任链模式的时候每增加一个处理类,就必须在责任链的实现类中手动增加到责任链中,具体代码基本就是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. 学javaweb 先学Servlet 应用理论很重要

    package cn.Reapsun.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.ser ...

  2. Asp.NetCore 自定义中间件

    这节演示一下自定义中间件,第一节我们讲到,中间件的处理流程就像一个俄罗斯套娃,那这种俄罗斯套娃型的流程内部是如何实现的呢,下面请看代码​. ​第一种写法是直接写在Configure方法中的,使用app ...

  3. JavaWeb——MySQL约束

    内容索引 1. DQL:查询语句 1. 排序查询 2. 聚合函数 3. 分组查询 4. 分页查询 2. 约束 3. 多表之间的关系 4. 范式 5. 数据库的备份和还原 DQL:查询语句 1. 排序查 ...

  4. Educational Codeforces Round 92 (Rated for Div. 2)

    A.LCM Problem 题意:最小公倍数LCM(x,y),处于[l,r]之间,并且x,y也处于[l,r]之间,给出l,r找出x,y; 思路:里面最小的最小公倍数就是基于l左端点的,而那个最小公倍数 ...

  5. Mybatis-Plus的应用场景及注入SQL原理分析

    一.背景 1.1 传统Mybatis的弊端 1.1.1 场景描述 假设有两张表:一张商品表.一张订单表,具体表的字段如下: 现有如下需求: 分别根据id查询商品表和订单表所有信息 根据支付状态和通知状 ...

  6. gparted 当分区空间大于1T 用gparted分区

    lsblkfdisk -lparted -s /dev/sdb mklabel msdos parted -s /dev/sdb mkpart primary 0 100%lsblk dfparted ...

  7. ln -s 新目录(最后一个目录新建images) 旧目录(删除最后的images目录)

    sudo yum install libvirt virt-install qemu-kvm 默认安装会启用一个NAT模式的bridgevirbr0 启动激活libvirtd服务 systemctl ...

  8. 基于多IP地址Web服务

    [Centos7.4版本] !!!测试环境我们首关闭防火墙和selinux [root@localhost ~]# systemctl stop firewalld [root@localhost ~ ...

  9. Linux_搭建Samba服务(认证访问)

    [RHEL8]-SMBserver:[RHEL7]-SMBclient !!!测试环境我们首关闭防火墙和selinux(SMBserver和SMBclient都需要) [root@localhost ...

  10. 040.Python进程和Join

    一  进程相关介绍 1.1 进程的概念(process) 进程就是正在运行的程序,它是操作系统中,资源分配的最小单位 资源分配:分配的是cpu和内存等物理资源 进程号是程的唯标识 同-个程序执行两次之 ...