设计模式-责任链
之前写代码的时候看到过有审批场景使用了责任链,当时大概看了一下代码实现,今天终于有时间抽出来梳理一下,下面是本文的大纲:
使用场景
审批场景的普遍应用
实际案例:HttpClient中的责任链模式
责任链模式在事件处理、日志记录和过滤器链中的应用
责任链模式实现方式一代码实现
接口和具体处理器类的设计
处理器类的链式结构
客户端使用责任链的示例
责任链模式实现方式二代码实现(简易版)
Spring框架的 @Order 注解的应用
利用 @Order 注解实现的责任链模式
客户端通过构造函数注入实现责任链
HttpClient中的责任链模式(之前遇到过)
使用场景
查了一下大概的使用场景,其实审批场景使用的会比较多,我记得自己第一次看到责任链的时候是在看HttpClient的代码的时候,用了责任链进行请求体的数据传递,只不过当时自己的工程能力还不是特别的完善,因此简单看了个大概就略过了,今天顺便一起梳理了。
-
当程序需要使用不同方式处理不同种类请求, 而且请求类型和顺序预先未知时, 可以使用责任链模式。该模式能将多个处理者连接成一条链。 接收到请求后, 它会 “询问” 每个处理者是否能够对其进行处理。 这样所有处理者都有机会来处理请求。
-
当必须按顺序执行多个处理者时, 可以使用该模式。无论你以何种顺序将处理者连接成一条链, 所有请求都会严格按照顺序通过链上的处理者。
-
如果所需处理者及其顺序必须在运行时进行改变, 可以使用责任链模式。如果在处理者类中有对引用成员变量的设定方法, 你将能动态地插入和移除处理者, 或者改变其顺序。

责任链常见的使用场景包括审批流程、事件处理、日志记录、过滤器链等。例如,在一个审批流程中,不同级别的审批人员可以组成一个责任链,每个审批人员处理自己能够处理的审批请求,如果自己无法处理,则将请求传递给下一个审批人员。这样可以动态地调整审批流程,而不需要修改整个系统的代码。
责任链结构

代码实现,方式一
先给一个责任链的实现代码,思路其实还好,有点类似链表的实现方式,每一个类尝试去进行处理,如果处理不了就交给下一个类,每一个类会按照顺序保存下一个类的地址,这是不是有点类似于链表的结构?当然其实审批流的场景也类似链表的结构,什么时候路由到下一个节点什么时候结束这些都可以收敛到类里面。
// 定义处理请求的接口
interface Handler {void handleRequest(Request request);
}// 具体处理器类
class ConcreteHandler1 implements Handler {private Handler nextHandler;public void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}@Overridepublic void handleRequest(Request request) {// 根据具体业务逻辑判断是否能处理请求if (request.getType().equals("Type1")) {System.out.println("ConcreteHandler1处理请求:" + request.getContent());} else {// 如果不能处理,则将请求传递给下一个处理器if (nextHandler != null) {nextHandler.handleRequest(request);} else {System.out.println("没有处理器能够处理该请求");}}}
}class ConcreteHandler2 implements Handler {private Handler nextHandler;public void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}@Overridepublic void handleRequest(Request request) {if (request.getType().equals("Type2")) {System.out.println("ConcreteHandler2处理请求:" + request.getContent());} else {if (nextHandler != null) {nextHandler.handleRequest(request);} else {System.out.println("没有处理器能够处理该请求");}}}
}// 请求类
class Request {private String type;private String content;public Request(String type, String content) {this.type = type;this.content = content;}public String getType() {return type;}public String getContent() {return content;}
}// 客户端使用责任链
public class ChainOfResponsibilityExample {public static void main(String[] args) {// 创建具体处理器ConcreteHandler1 handler1 = new ConcreteHandler1();ConcreteHandler2 handler2 = new ConcreteHandler2();// 设置责任链关系handler1.setNextHandler(handler2);// 创建请求Request request1 = new Request("Type1", "请求类型1");Request request2 = new Request("Type2", "请求类型2");Request request3 = new Request("Type3", "请求类型3");// 客户端提交请求handler1.handleRequest(request1);handler1.handleRequest(request2);handler1.handleRequest(request3);}
}
代码实现,方式二
另外其实还有一个非常简单的实现思路,我记得之前自己看到的责任链实现是基于@Order注解来实现的,找GPT实现了一版当时的代码case,示例如下,这种实现其实能够解决大部分的问题并且非常的简单
public interface Handler {void handleRequest(Request request);
}@Component
@Order(1)
public class ConcreteHandler1 implements Handler {@Overridepublic void handleRequest(Request request) {System.out.println("ConcreteHandler1处理请求:" + request.getContent());}
}@Component
@Order(2)
public class ConcreteHandler2 implements Handler {@Overridepublic void handleRequest(Request request) {System.out.println("ConcreteHandler2处理请求:" + request.getContent());}
}@Component
public class ChainClient {private final List<Handler> handlers;@Autowiredpublic ChainClient(List<Handler> handlers) {this.handlers = handlers;}public void executeChain(Request request) {for (Handler handler : handlers) {handler.handleRequest(request);}}
}
在这个例子中,ConcreteHandler1 和 ConcreteHandler2 使用 @Order 注解标记了它们的执行顺序。客户端类 ChainClient 通过构造函数注入所有的处理器,并按照它们的顺序循环调用 handleRequest 方法,从而触发责任链的执行。
HttpClient的责任链
HttpClient 库在内部使用了责任链模式的一种形式。具体而言,它采用了拦截器(Interceptor)机制,这是责任链的一种实现方式。
拦截器机制在 HttpClient 中的工作方式如下:
请求拦截器: 请求拦截器负责在发送之前修改即将发送的 HTTP 请求。它们可以添加头部信息、修改请求方法,或在请求上执行其他操作。
响应拦截器: 响应拦截器负责在将响应返回给调用者之前处理收到的 HTTP 响应。它们可以从响应中提取信息、处理重定向,或在响应上执行其他操作。
执行拦截器: 执行拦截器负责执行 HTTP 请求并获取响应。它在整个请求生命周期中扮演了至关重要的角色,从请求的创建到响应的处理。
每个拦截器都是责任链的一部分,并且链式执行。
写完之后忽然想起了自己之前稍微整理的一版责任链,当时大概是刚开始学java的时候整理的,自己梳理了一个大概的流程图,提供一下跳转链接
https://blog.csdn.net/xiaocaij_icai/article/details/125578282?spm=1001.2014.3001.5501
相关文章:
设计模式-责任链
之前写代码的时候看到过有审批场景使用了责任链,当时大概看了一下代码实现,今天终于有时间抽出来梳理一下,下面是本文的大纲: 使用场景 审批场景的普遍应用 实际案例:HttpClient中的责任链模式 责任链模式在事件处理、…...
ubuntu怎么安装docker
sudo apt-get update sudo apt-get install \ ca-certificates \ curl \ gnupg \ lsb-release 添加Docker官方的GPG密钥 curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -使用以下命令设置稳定存储库。要添加 夜间或测试存储库&…...
UE4运用C++和框架开发坦克大战教程笔记(十五)(第46~48集)
UE4运用C和框架开发坦克大战教程笔记(十五)(第46~48集) 46. 批量加载 UClass 功能测试批量加载多个同类 UClass 资源 47. 创建单个资源对象测试加载并创建单个 UClass 资源对象 48. 创建同类资源对象 46. 批量加载 UClass 功能 逻…...
《Linux系列》Linux虚拟机,LVM逻辑卷扩容,xfs文件系统扩容
Linux虚拟机,LVM逻辑卷扩容,xfs文件系统扩容 1 虚拟机配置介绍 在创建虚拟机的时候只给了20G磁盘空间大小,但是现在需求变更,想要增加到40G磁盘空间大小,所以需要通过两步扩容磁盘空间。 系统版本是Centos7 根目录…...
springboot(ssm动漫手办商城 动漫周边商系统Java系统
springboot(ssm动漫手办商城 动漫周边商系统Java系统 开发语言:Java 框架:springboot(可改ssm) vue JDK版本:JDK1.8(或11) 服务器:tomcat 数据库:mysql 5.7…...
卸载 MariaDB:
如果你想将 MariaDB 5.5.68 替换为 MySQL 8,请按照以下步骤操作。在执行这些步骤之前,请确保你已经备份了所有重要的数据库和数据,以防发生意外情况。 1. 卸载 MariaDB: 使用适合你系统的包管理器卸载 MariaDB。在 CentOS/RHEL …...
javaweb总览
javaweb需要学习哪些技术 前端web开发: 技术描述HTML用于构建网站的基础结构的css用于美化页面的,作用和化妆或者整容作用一样JavaScript实现网页和用户的交互Vue主要用于将数据填充到html页面上的Element主要提供了一些非常美观的组件Nginx一款web服务…...
树,二叉树及其相关知识
1.树概念及结构 1.1树的概念 树是一种非线性的数据结构,它是由n(n>0)个有限结点组成一个具有层次关系的集合。把它叫做树是因 为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。 有一个特殊的结点&#…...
NumPy必知必会50例 | 5. 高级数组操作:成为 NumPy 数组的忍者
文章目录 5. 高级数组操作:成为 NumPy 数组的忍者数组重塑:变形大师例子:从一维到二维 数组合并:忍者团队联合例子:水平和垂直合并 数组分割:忍者的快速撤退例子:水平和垂直分割 5. 高级数组操作…...
《WebKit 技术内幕》学习之五(3): HTML解释器和DOM 模型
3 DOM的事件机制 基于 WebKit 的浏览器事件处理过程:首先检测事件发生处的元素有无监听者,如果网页的相关节点注册了事件的监听者则浏览器会将事件派发给 WebKit 内核来处理。另外浏览器可能也需要处理这样的事件(浏览器对于有些事件必须响应…...
extends 和 implements
以下是 extends 和 implements 在Java代码中的区别和示例: 示例1:使用 extends 实现类继承 // 定义一个父类 Animal public class Animal {public void eat() {System.out.println("动物在吃东西");}public void sleep() {System.out.printl…...
响应拦截器的 return Promise.reject(res.data.message)
今天在看老师讲解代码的时候,解决了我心中的一些疑惑。 在做excel文件导出的时候,没有告诉浏览器文件的格式是Blod产生了报错。 看下图: 可以看到下面的内容:如果业务成功 返回 res.data 如果业务失败,给出错误信息的提示,将这个错误抛出去。 因此我们在发送一个…...
Windows下 VS2022 编译OpenSSL 库
SSL是Secure Sockets Layer(安全套接层协议)的缩写,可以在Internet上提供秘密性传输。Netscape公司在推出第一个Web浏览器的同时,提出了SSL协议标准。其目标是保证两个应用间通信的保密性和可靠性,可在服务器端和用户端同时实现支持。已经成为Internet上保密通讯的工业标准…...
【GitHub项目推荐--一个简单的绘图应用程序(Rust + GTK4)】【转载】
一个用 Rust 和 GTK4 编写的简单的绘图应用程序来创建手写笔记。 Rnote 旨在成为一个简单但实用的笔记应用程序,用于手绘或注释图片或文档。它最终能够导入/导出各种媒体文件格式。而且输出的作品是基于矢量的,这使其在编辑和更改内容时非常灵活。 地址…...
【算法小记】——机器学习中的概率论和线性代数,附线性回归matlab例程
内容包含笔者个人理解,如果错误欢迎评论私信告诉我 线性回归matlab部分参考了up主DR_CAN博士的课程 机器学习与概率论 在回归拟合数据时,根据拟合对象,可以把分类问题视为一种简答的逻辑回归。在逻辑回归中算法不去拟合一段数据而是判断输入…...
MySQL数据库的锁机制
目录 一、引言 二、锁的类型及作用 2.1 行级锁 2.2 间隙锁与临键锁 2.3 共享锁与排他锁 2.4 意向锁 2.5 表级锁 2.6 元数据锁 三、锁的管理与优化 3.1 合理设置事务隔离级别 3.2 避免长事务 3.3 索引优化 3.4 明确锁定范围 3.5 避免不必要的全表扫描 四、实战分…...
解决 conda新建虚拟环境只有一个conda-meta文件&conda新建虚拟环境不干净
像以前一样通过conda 新建虚拟环境时发现环境一团糟,首先新建虚拟环境 conda create -n newenv这时候activate newenv,通过pip list,会发现有很多很多的包,都是我在其他环境用到的。但诡异的是,来到anaconda下env的目…...
React16源码: React中的completeWork对HostText处理含更新的源码实现
HostText 1 )概述 在 completeWork 中 对 HostText的处理在第一次挂载和后续更新的不同条件下进行操作 第一次挂载主要是创建实例后续更新其实也是重新创建实例 2 )源码 定位到 packages/react-reconciler/src/ReactFiberCompleteWork.js#L663 到 c…...
网络协议与攻击模拟_07UDP协议
一、简单概念 1、UDP协议简介 UDP(用户数据报)协议,是传输层的协议。不需要建立连接,直接发送数据,不会重新排序,不需要确认。 2、UDP报文字段 源端口目的端口UDP长度UDP校验和 3、常见的UDP端口号 5…...
生命在于折腾——WeChat机器人的研究和探索
一、前言 2022年,我玩过原神,当时看到了云崽的QQ机器人,很是感兴趣,支持各种插件,查询游戏内角色相关信息,当时我也自己写了几个插件,也看到很多大佬编写的好玩的插件,后来因为QQ不…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
Qt 事件处理中 return 的深入解析
Qt 事件处理中 return 的深入解析 在 Qt 事件处理中,return 语句的使用是另一个关键概念,它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别:不同层级的事件处理 方…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...
Axure 下拉框联动
实现选省、选完省之后选对应省份下的市区...
