遇到无序多变请求怎么办,可以试试责任链模式

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

一、责任链模式介绍

其实在日常生活中,有不少使用责任链的场景。比如公司采购审批流程,需要各个部门领导的批准同意。在责任链模式中,客户端只需要将请求发送到责任链上,无须关心请求的处理细节和传递,请求会自动进行传递。

1.1 责任链模式的结构

责任链模式结构的核心在于引入了一个抽象处理类,所以主要包含两个部分

  • 一个抽象Handler类
    • 因为责任链的存在,需要定义下一个handler的引用,才能形成一个链条
    • 有了下一个handler引用,所以要对引用进行调用和管理,于是需要setNext()getNext() 方法
    • 此外由于不同handler处理请求的方式不一致,所以要在其中定义一个抽象的请求方法handleRequest()
  • 一系列具体的Handler处理类

具体结构大致如下所示:

image-20220404203259612

  • abstract Handler:抽象处理者,定义一个处理请求的接口,内部包含抽象处理方法和后继具体处理者
  • Handler1、Handler2:具体处理者,具体实现抽象处理者的方法,并对请求做一些逻辑处理
  • Client:客户端,使用职责链模式

1.2 职责链模式的实现

根据上面的类图,可以实现如下代码:

/*** @description: 抽象处理类* @date: 2022/4/4*/
public abstract class Handler {private Handler successor;public Handler getSuccessor() {return successor;}public void setSuccessor(Handler successor) {this.successor = successor;}/*** 处理请求的抽象方法* @param request 请求*/public abstract void handleRequest(String request);
}
/*** @description: 具体处理者1* @date: 2022/4/4*/
public class Handler1 extends Handler{private String handler;public Handler1(String handler) {this.handler = handler;}@Overridepublic void handleRequest(String request) {if ("handler1".equals(request)) {System.out.println("具体处理者handler1进行请求处理");} else {if (getSuccessor() != null) {//如果指向下一个具体处理者getSuccessor().handleRequest(request);} else {System.out.println("没有处理者进行处理");}}}
}
/*** @description: 具体处理者2* @date: 2022/4/4*/
public class Handler2 extends Handler{private String handler;public Handler2(String handler) {this.handler = handler;}@Overridepublic void handleRequest(String request) {if ("handler2".equals(request)) {System.out.println("具体处理者handler2进行请求处理");} else {if (getSuccessor() != null) {getSuccessor().handleRequest(request);} else {System.out.println("请求没有被任何处理者处理");}}}
}
/*** @description: 客户端类* @date: 2022/4/4*/
public class Client {public static void main(String[] args) {Handler handler1 = new Handler1("handler1");Handler handler2 = new Handler2("handler2");handler1.setSuccessor(handler2);handler1.handleRequest("handler1");handler1.handleRequest("handler2");}
}

测试结果:

具体处理者handler1进行请求处理
具体处理者handler2进行请求处理

二、责任链模式的应用场景

责任链适用的应用场景有:

  1. 当程序需要使用不同方式来处理不同种类的请求,而且各个请求类型和顺

职责链模式最常见的应用就是用来开发各种框架的过滤器和拦截器,比如Spring Interceptor和Servlet Filter

2.1 在Servlet Filter中的应用

Filter 可以实现对HTTP 请求的过滤功能,比如鉴权、限流、记录日志、验证参数等等。比如一些Servlet 容器(TomCat、Jetty等)就支持Filter的过滤功能。以TomCat 为例:

image-20220404214532930

所以当Servlet 请求到来时,首先会经过Filter 处理,最后再到达Servlet实例。我这里选取的TomCat版本是SpringBoot自带的9.0,先来看看FilterChain 的接口:

public interface FilterChain {//Filter具体实现void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}

ApplicationFilterChain是责任链模式的具体实现类:

public final class ApplicationFilterChain implements FilterChain {private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0]; //Filter配置数组private int pos = 0; //执行Filter的序号private int n = 0;	 //目前Filter的个数private Servlet servlet = null;public ApplicationFilterChain() {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {//Filter 具体实现//...}public static ServletRequest getLastServicedRequest() {return (ServletRequest)lastServicedRequest.get();}public static ServletResponse getLastServicedResponse() {return (ServletResponse)lastServicedResponse.get();}void addFilter(ApplicationFilterConfig filterConfig) {ApplicationFilterConfig[] newFilters = this.filters;int var3 = newFilters.length;for(int var4 = 0; var4 < var3; ++var4) {ApplicationFilterConfig filter = newFilters[var4];if (filter == filterConfig) {return;}}//增加Filterif (this.n == this.filters.length) {newFilters = new ApplicationFilterConfig[this.n + 10];System.arraycopy(this.filters, 0, newFilters, 0, this.n);this.filters = newFilters;}this.filters[this.n++] = filterConfig;}
}

2.2 在Spring Interceptor中的应用

和Servlet Filter类似,在Spring 中也有对应的过滤器 Interceptor。它是由Spring MVC 框架来实现,借一张来自《设计模式之美》的图片来说明:

image-20220404221601450

客户端发送请求,首先会经过Servlet Filter,然后再经过Spring Interceptor,最后再到达具体的业务中。

和Filter一样,Interceptor 中也是基于责任链模式来实现的,与之相对的HandlerInterceptor是抽象处理接口:

public interface HandlerInterceptor {default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return true;}default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {}default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {}
}

会有各种具体处理类的实现:

image-20220404222327991

此外在其他框架中也存在着职责链模式的使用,比如Dubbo Filter、Netty ChannelPipeline等等

三、责任链模式实战

3.1 模拟三级审批责任链

简单利用职责链来设计三级审批:

public static void main(String[] args) {//设计审批责任链Handler handler = new FirstHandler().setNext(new SecondHandler().setNext(new ThirdHandler()));handler.doHandler("firstRequest");}//抽象处理类static abstract class Handler {private Handler next;public Handler getNext() {return next;}public Handler setNext(Handler next) {this.next = next;return this;}public abstract void doHandler(String request);}//第一级审批人static class FirstHandler extends Handler {@Overridepublic void doHandler(String request) {System.out.println("第一个审批处理点审批中...");if (request == null || request == "") {System.out.println("第一个审批节点的请求为空!");;}System.out.println("第一个审批处理点审批完成");super.next.doHandler("secondRequest");}}//第二级审批人static class SecondHandler extends Handler {@Overridepublic void doHandler(String request) {System.out.println("第二个审批处理点审批中...");if (request == null || request == ""){System.out.println("第二个审批节点的请求为空!");}System.out.println("第一个审批处理点审批完成");super.next.doHandler("thirdRequest");}}//第三级审批人static class ThirdHandler extends Handler {@Overridepublic void doHandler(String request) {System.out.println("第三个审批处理点审批中...");Handler next = super.next;if (next == null){System.out.println("审批结束");}}}

3.2 模拟在618大促期间的业务系统上线审批流程场景:

像是这些⼀线电商类的互联⽹公司,阿⾥、京东、拼多多等,在618期间都会做⼀些运营活动场景以及 提供的扩容备战,就像过年期间百度的红包⼀样。但是所有开发的这些系统都需要陆续的上线,因为临 近618有时候也有⼀些紧急的调整的需要上线,但为了保障线上系统的稳定性是尽可能的减少上线的, 也会相应的增强审批⼒度。就像⼀级响应、⼆级响应⼀样。

⽽这审批的过程在随着特定时间点会增加不同级别的负责⼈加⼊,每个⼈就像责任链模式中的每⼀个核 ⼼点。对于研发并不需要关⼼具体的审批流程处理细节,只需要知道这个上线更严格,级别也更 ⾼,但对于研发⼈员来说同样是点击相同的提审按钮,等待审核。

使用责任链模式可以将各个服务模块按照一、二、三级进行分离,每个级别可以像Filter一样用Successor下一个级别的方法进行调用。具体结构图如下(来自《重学Java设计模式》)

image-20220404223642273

具体代码结构

│——AuthInfo.java
│——AuthLink.java
│
├─business
│     AuthService.java
│
└─implLevel1AuthLink.javaLevel2AuthLink.javaLevel3AuthLink.java

实现代码:

/*** @description: 链路抽象审批* @date: 2022/4/4*/
public abstract class AuthLink {/**时间格式化**/protected SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");/**级别人员ID**/protected String levelUserId;/**级别人员姓名**/protected String levelUserName;/**下一个链路**/private AuthLink next;public AuthLink(String levelUserId, String levelUserName) {this.levelUserId = levelUserId;this.levelUserName = levelUserName;}public AuthLink next() {return next;}public AuthLink appendNext(AuthLink next) {this.next = next;return this;}/**每个具体处理者必须实现的方法**/public abstract AuthInfo doAuth(String uId, String orderId, Date authDate);
}
/*** @description: 责任链中返回对象的定义* @date: 2022/4/4*/
public class AuthInfo {private String code;private String info = " ";public AuthInfo(String code, String... infos) { //...表示可变长参数,可以传入多个参数this.code = code;for (String s : infos) {this.info = this.info.concat(s);}}public String getCode() {return code;}public void setCode(String code) {this.code = code;}public String getInfo() {return info;}public void setInfo(String info) {this.info = info;}
}
/*** @description: 一级审核人* @date: 2022/4/4*/
public class Level1AuthLink extends AuthLink {public Level1AuthLink(String levelUserId, String levelUserName) {super(levelUserId, levelUserName);}@Overridepublic AuthInfo doAuth(String uId, String orderId, Date authDate) {Date date = AuthService.queryAuthInfo(levelUserId, orderId);if (null == date) {return new AuthInfo("0001", "单号", orderId, "状态:一级审批负责人", levelUserName);}AuthLink next = super.next();if (null == next) {return new AuthInfo("0000", "单号", orderId, "状态:一级审批负责人", " 时间:", f.format(date), "审批人:", levelUserName);}return next.doAuth(uId, orderId, authDate);}
}
/*** @description: 测试类* @date: 2022/4/5*/
public class ApiTest {private Logger logger = LoggerFactory.getLogger(ApiTest.class);@Testpublic void test_AuthLink() throws ParseException {//创建审批链条AuthLink authLink = new Level3AuthLink("1000013", "王工").appendNext(new Level2AuthLink("1000012", "张经理").appendNext(new Level1AuthLink("1000011", "赵总裁")));logger.info("测试结果:{}", JSON.toJSONString(authLink.doAuth("ethan", "100099800423123", new Date())));//将单号和用户id存入authMap中AuthService.auth("1000013", "100099800423123");logger.info("测试结果:{}", "模拟二级审批,王工");logger.info("测试结果:{}",JSON.toJSONString(authLink.doAuth("ethan", "100099800423123", new Date())));AuthService.auth("1000012", "100099800423123");logger.info("测试结果:{}", "模拟二级负责人审批,张经理");logger.info("测试结果:{}", JSON.toJSONString(authLink.doAuth("ethan", "100099800423123", new Date())));AuthService.auth("1000011", "100099800423123");logger.info("测试结果:{}", "模拟二级负责人审批,赵总裁");logger.info("测试结果:{}", JSON.toJSONString(authLink.doAuth("ethan", "100099800423123", new Date())));}
}

最后的测试结果:

10:05:08.675 [main] INFO  ApiTest - 测试结果:{"code":"0001","info":" 单号:100099800423123 状态:待三级审批 王工"}
10:05:08.679 [main] INFO  ApiTest - 测试结果:模拟三级审批,王工
10:05:08.680 [main] INFO  ApiTest - 测试结果:{"code":"0001","info":" 单号:100099800423123 状态:待二级审批负责人张经理"}
10:05:08.680 [main] INFO  ApiTest - 测试结果:模拟二级负责人审批,张经理
10:05:08.680 [main] INFO  ApiTest - 测试结果:{"code":"0001","info":" 单号100099800423123状态:待一级审批负责人赵总裁"}
10:05:08.680 [main] INFO  ApiTest - 测试结果:模拟一级负责人审批,赵总裁
10:05:08.680 [main] INFO  ApiTest - 测试结果:{"code":"0000","info":" 单号100099800423123状态:一级审批完成负责人 时间:2023-09-11 10:05:08审批人:赵总裁"}

参考资料

《设计模式之美》

http://c.biancheng.net/view/4024.html

《重学Java设计模式》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/592880.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UDP通信(服务器-客户端)

一、 UDP服务器-客户端通信 UDP&#xff08;User Datagram Protocol&#xff09;是一种面向无连接的传输层协议&#xff0c;它提供了一种简单的、不可靠的数据传输服务。与TCP&#xff08;Transmission Control Protocol&#xff09;不同&#xff0c;UDP不建立连接&#xff0c;…

基于Kettle开发的web版数据集成开源工具(data-integration)-部署篇

目录 &#x1f4da;第一章 前言&#x1f4d7;背景&#x1f4d7;目的&#x1f4d7;总体方向 &#x1f4da;第二章 下载编译&#x1f4d7;下载&#x1f4d7;编译 &#x1f4da;第三章 部署&#x1f4d7;准备工作&#x1f4d5; 安装数据库&redis&consul&#x1f4d5; 修改…

计算机毕业设计-------基于JSP+Servlet的毕业生离校管理系统

需求分析 使用JSPServletMysql技术设计一个毕业生离校管理系统, 整个系统采用BS架构, 为高校方便进行毕业生离校流程进行统一的离校流程, 极大的减少了大量学生同时离校的过程中杂乱的情况, 整个系统分为学生, 教务处, 辅导员, 图书馆, 宿管, 财务处, 系办公室, 管理员登等角色…

【华为机试】2023年真题B卷(python)-考古问题

一、题目 题目描述&#xff1a; 考古问题&#xff0c;假设以前的石碑被打碎成了很多块&#xff0c;每块上面都有一个或若干个字符&#xff0c;请你写个程序来把之前石碑上文字可能的组合全部写出来&#xff0c;按升序进行排列。 二、输入输出 三、示例 示例1: 输入输出示例仅供…

了解Apache 配置与应用

本章内容 理解 Apache 连接保持 掌握 Apache 的访问控制 掌握 Apache 日志管理的方法 Apache HTTP Server 之所以受到众多企业的青睐&#xff0c;得益于其代码开源、跨平台、功能 模块化、可灵活定制等诸多优点&#xff0c;不仅性能稳定&#xff0c;在安全性方面的表现也十分…

【设计模式-2】原型模式的原理、代码实现及类图展示

我们一定对类的实例化比较熟悉&#xff0c;前面我们说的单例、还有3种工厂模式都是通过new关键字来创建对象&#xff0c;下面我们来了解一种新的对象创建的方式。 1. 定义 原型模式也是一种创建型的设计模式&#xff0c;实现和原理总体比较简单&#xff0c;一句话总结呢&#…

Weblogic安全漫谈(二)

前言 继本系列上篇从CVE-2015-4852入手了解T3协议的构造后&#xff0c;本篇继续分析开启T3反序列化魔盒后的修复与绕过。 Weblogic对于10.3.6推出了p20780171和p22248372用于修复CVE-2015-4852&#xff0c;在补丁详情中又提示了p21984589是它的超集&#xff0c;所以可以直接装…

通过软盘拷贝文件 - 华为OD统一考试

OD统一考试(B卷) 分值&#xff1a; 200分 题解&#xff1a; Java / Python / C 题目描述 有一名科学家想要从一台古董电脑中拷贝文件到自己的电脑中加以研究但此电脑除了有一个3.5寸软盘驱动器以外&#xff0c;没有任何手段可以将文件持贝出来&#xff0c;而且只有一张软盘可以…

MySQL将多条数据合并成一条的完整示例

数据库中存的是多条数据&#xff0c;展示的时候需要合并成一条 数据表存储形式如下图 以type分组&#xff0c;type相同的算一条&#xff0c;且保留image和link的所有数据&#xff0c;用groupBy只保留一条数据 解决方案&#xff1a;用GROUP_CONCAT 完整语法如下 group_concat…

从有向带权图判断最短路径里各目标顶点顺序

对如下有向带权图&#xff0c;若采用迪杰斯特拉(Dijkstra)算法求从源点a到其他各顶点的最短路径&#xff0c;则得到的第一路径的目标顶点是b&#xff0c;第二条最短路径的目标顶点是c&#xff0c;后续得到的其余各最短路径的目标顶点依次是() A.d,e,f B.e,d,f C.f,d,e D.f,…

linux-6.0 内核存储栈全景图

linux 存储栈原图地址&#xff1a;https://www.thomas-krenn.com/en/wiki/Linux_Storage_Stack_Diagram

自动驾驶TPM技术杂谈 ———— ODDODC

文章目录 介绍研究现状主流相关定义国标定义SAE定义WP29定义 ODD主流构建框架NHTSA ODD构建框架SAE AVSC ODD构建框架PEGASUS 6层模型BSI ODD构建框架 设计运行条件的原则ODC 的设计原则ODC 元素的制定原则ODC 的使用原则 设计运行条件元素ODD 元素驾乘人员状态4车辆状态 ODC 描…

3分钟Alibaba Cloud Linux镜像操作系统详解

Alibaba Cloud Linux是基于龙蜥社区OpenAnolis龙蜥操作系统Anolis OS的阿里云发行版&#xff0c;针对阿里云服务器ECS做了大量深度优化&#xff0c;Alibaba Cloud Linux由阿里云官方免费提供长期支持和维护LTS&#xff0c;Alibaba Cloud Linux完全兼容CentOS/RHEL生态和操作方式…

深入了解隧道代理HTTP的协议与技术细节

隧道代理HTTP&#xff0c;作为一种网络通信的桥梁技术&#xff0c;其背后的协议与技术细节承载着网络世界的无尽奥秘。对于技术人员而言&#xff0c;深入了解这些细节&#xff0c;不仅有助于优化网络性能&#xff0c;还能为网络安全提供坚实的保障。 一、隧道代理HTTP的协议基…

2024阿里云服务器租赁优惠价格表_ECS和轻量应用服务器配置报价

阿里云服务器租用价格表大全&#xff0c;云服务器一年费用、一个月价格以及1小时收费明细&#xff0c;阿里云2核2G3M带宽轻量服务器一年61元、2核4G4M带宽轻量服务器一年165元12个月&#xff0c;ECS云服务器e系列2核2G配置99元一年、2核4G服务器30元3个月、2核4G配置365元一年、…

二维码、条形码识别

一. 场景介绍 二维码和条形码包含很多信息&#xff0c;对二维码和条形码识别对信息抽取具有重要意义。下面介绍两种二维码识别的方法&#xff0c;并用python实现。 二. 代码实现 import os import cv2 from cv2.wechat_qrcode import WeChatQRCode from pyzbar import pyzba…

深度生成模型之GAN基础 ->(个人学习记录笔记)

文章目录 深度生成模型之GAN基础生成对抗网络1. 生成对抗网络如何生成数据2. 生成对抗原理3. GAN的核心优化目标4. D的优化5. GAN的理想状态6. GAN的训练7. 梯度不稳定与模式崩塌(collapse mode)问题8. 梯度消失问题 深度生成模型之GAN基础 生成对抗网络 1. 生成对抗网络如何…

三、HTML元素

一、HTML元素 HTML 文档由 HTML 元素定义。 *开始标签常被称为起始标签&#xff08;opening tag&#xff09;&#xff0c;结束标签常称为闭合标签&#xff08;closing tag&#xff09;。 二、HTML 元素语法 HTML 元素以开始标签起始。HTML 元素以结束标签终止。元素的内容是…

python算法问题,求两个字符串的最长公共子序列长度

对于问题&#xff0c;两个字符串的最长公共子序列长度进行求解&#xff0c;首先要知道子序列的定义&#xff0c;如果说给定一个字符串&#xff0c;对这个字符串中的原有字符进行不改变字符相对位置的删除&#xff0c;这里的相对位置就是处于前还是后的相对关系&#xff0c;进行…

[足式机器人]Part2 Dr. CAN学习笔记-自动控制原理Ch1-7Lead Compensator超前补偿器(调节根轨迹)

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记-自动控制原理Ch1-7Lead Compensator超前补偿器&#xff08;调节根轨迹&#xff09; 1. Plot Rootlocus 绘制根轨迹2. System Performance 系统表现3. 改善/加快收敛速度4. 超前补偿器 Lead Compe…