当前位置: 首页 > news >正文

设计模式-责任链

之前写代码的时候看到过有审批场景使用了责任链,当时大概看了一下代码实现,今天终于有时间抽出来梳理一下,下面是本文的大纲:

使用场景
审批场景的普遍应用
实际案例:HttpClient中的责任链模式
责任链模式在事件处理、日志记录和过滤器链中的应用
责任链模式实现方式一代码实现
接口和具体处理器类的设计
处理器类的链式结构
客户端使用责任链的示例
责任链模式实现方式二代码实现(简易版)
Spring框架的 @Order 注解的应用
利用 @Order 注解实现的责任链模式
客户端通过构造函数注入实现责任链
HttpClient中的责任链模式(之前遇到过)

使用场景

查了一下大概的使用场景,其实审批场景使用的会比较多,我记得自己第一次看到责任链的时候是在看HttpClient的代码的时候,用了责任链进行请求体的数据传递,只不过当时自己的工程能力还不是特别的完善,因此简单看了个大概就略过了,今天顺便一起梳理了。

  1. 当程序需要使用不同方式处理不同种类请求, 而且请求类型和顺序预先未知时, 可以使用责任链模式。该模式能将多个处理者连接成一条链。 接收到请求后, 它会 “询问” 每个处理者是否能够对其进行处理。 这样所有处理者都有机会来处理请求。

  2. 当必须按顺序执行多个处理者时, 可以使用该模式。无论你以何种顺序将处理者连接成一条链, 所有请求都会严格按照顺序通过链上的处理者。

  3. 如果所需处理者及其顺序必须在运行时进行改变, 可以使用责任链模式。如果在处理者类中有对引用成员变量的设定方法, 你将能动态地插入和移除处理者, 或者改变其顺序。
    在这里插入图片描述

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

责任链结构
在这里插入图片描述

代码实现,方式一

先给一个责任链的实现代码,思路其实还好,有点类似链表的实现方式,每一个类尝试去进行处理,如果处理不了就交给下一个类,每一个类会按照顺序保存下一个类的地址,这是不是有点类似于链表的结构?当然其实审批流的场景也类似链表的结构,什么时候路由到下一个节点什么时候结束这些都可以收敛到类里面。

// 定义处理请求的接口
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

相关文章:

设计模式-责任链

之前写代码的时候看到过有审批场景使用了责任链&#xff0c;当时大概看了一下代码实现&#xff0c;今天终于有时间抽出来梳理一下&#xff0c;下面是本文的大纲&#xff1a; 使用场景 审批场景的普遍应用 实际案例&#xff1a;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和框架开发坦克大战教程笔记&#xff08;十五&#xff09;&#xff08;第46~48集&#xff09; 46. 批量加载 UClass 功能测试批量加载多个同类 UClass 资源 47. 创建单个资源对象测试加载并创建单个 UClass 资源对象 48. 创建同类资源对象 46. 批量加载 UClass 功能 逻…...

《Linux系列》Linux虚拟机,LVM逻辑卷扩容,xfs文件系统扩容

Linux虚拟机&#xff0c;LVM逻辑卷扩容&#xff0c;xfs文件系统扩容 1 虚拟机配置介绍 在创建虚拟机的时候只给了20G磁盘空间大小&#xff0c;但是现在需求变更&#xff0c;想要增加到40G磁盘空间大小&#xff0c;所以需要通过两步扩容磁盘空间。 系统版本是Centos7 根目录…...

springboot(ssm动漫手办商城 动漫周边商系统Java系统

springboot(ssm动漫手办商城 动漫周边商系统Java系统 开发语言&#xff1a;Java 框架&#xff1a;springboot&#xff08;可改ssm&#xff09; vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&#xff1a;mysql 5.7&#xf…...

卸载 MariaDB:

如果你想将 MariaDB 5.5.68 替换为 MySQL 8&#xff0c;请按照以下步骤操作。在执行这些步骤之前&#xff0c;请确保你已经备份了所有重要的数据库和数据&#xff0c;以防发生意外情况。 1. 卸载 MariaDB&#xff1a; 使用适合你系统的包管理器卸载 MariaDB。在 CentOS/RHEL …...

javaweb总览

javaweb需要学习哪些技术 前端web开发&#xff1a; 技术描述HTML用于构建网站的基础结构的css用于美化页面的&#xff0c;作用和化妆或者整容作用一样JavaScript实现网页和用户的交互Vue主要用于将数据填充到html页面上的Element主要提供了一些非常美观的组件Nginx一款web服务…...

树,二叉树及其相关知识

1.树概念及结构 1.1树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因 为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 有一个特殊的结点&#…...

NumPy必知必会50例 | 5. 高级数组操作:成为 NumPy 数组的忍者

文章目录 5. 高级数组操作&#xff1a;成为 NumPy 数组的忍者数组重塑&#xff1a;变形大师例子&#xff1a;从一维到二维 数组合并&#xff1a;忍者团队联合例子&#xff1a;水平和垂直合并 数组分割&#xff1a;忍者的快速撤退例子&#xff1a;水平和垂直分割 5. 高级数组操作…...

《WebKit 技术内幕》学习之五(3): HTML解释器和DOM 模型

3 DOM的事件机制 基于 WebKit 的浏览器事件处理过程&#xff1a;首先检测事件发生处的元素有无监听者&#xff0c;如果网页的相关节点注册了事件的监听者则浏览器会将事件派发给 WebKit 内核来处理。另外浏览器可能也需要处理这样的事件&#xff08;浏览器对于有些事件必须响应…...

extends 和 implements

以下是 extends 和 implements 在Java代码中的区别和示例&#xff1a; 示例1&#xff1a;使用 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 如果业务失败,给出错误信息的提示&#xff0c;将这个错误抛出去。 因此我们在发送一个…...

Windows下 VS2022 编译OpenSSL 库

SSL是Secure Sockets Layer(安全套接层协议)的缩写,可以在Internet上提供秘密性传输。Netscape公司在推出第一个Web浏览器的同时,提出了SSL协议标准。其目标是保证两个应用间通信的保密性和可靠性,可在服务器端和用户端同时实现支持。已经成为Internet上保密通讯的工业标准…...

【GitHub项目推荐--一个简单的绘图应用程序(Rust + GTK4)】【转载】

一个用 Rust 和 GTK4 编写的简单的绘图应用程序来创建手写笔记。 Rnote 旨在成为一个简单但实用的笔记应用程序&#xff0c;用于手绘或注释图片或文档。它最终能够导入/导出各种媒体文件格式。而且输出的作品是基于矢量的&#xff0c;这使其在编辑和更改内容时非常灵活。 地址…...

【算法小记】——机器学习中的概率论和线性代数,附线性回归matlab例程

内容包含笔者个人理解&#xff0c;如果错误欢迎评论私信告诉我 线性回归matlab部分参考了up主DR_CAN博士的课程 机器学习与概率论 在回归拟合数据时&#xff0c;根据拟合对象&#xff0c;可以把分类问题视为一种简答的逻辑回归。在逻辑回归中算法不去拟合一段数据而是判断输入…...

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 新建虚拟环境时发现环境一团糟&#xff0c;首先新建虚拟环境 conda create -n newenv这时候activate newenv&#xff0c;通过pip list&#xff0c;会发现有很多很多的包&#xff0c;都是我在其他环境用到的。但诡异的是&#xff0c;来到anaconda下env的目…...

React16源码: React中的completeWork对HostText处理含更新的源码实现

HostText 1 &#xff09;概述 在 completeWork 中 对 HostText的处理在第一次挂载和后续更新的不同条件下进行操作 第一次挂载主要是创建实例后续更新其实也是重新创建实例 2 &#xff09;源码 定位到 packages/react-reconciler/src/ReactFiberCompleteWork.js#L663 到 c…...

网络协议与攻击模拟_07UDP协议

一、简单概念 1、UDP协议简介 UDP&#xff08;用户数据报&#xff09;协议&#xff0c;是传输层的协议。不需要建立连接&#xff0c;直接发送数据&#xff0c;不会重新排序&#xff0c;不需要确认。 2、UDP报文字段 源端口目的端口UDP长度UDP校验和 3、常见的UDP端口号 5…...

生命在于折腾——WeChat机器人的研究和探索

一、前言 2022年&#xff0c;我玩过原神&#xff0c;当时看到了云崽的QQ机器人&#xff0c;很是感兴趣&#xff0c;支持各种插件&#xff0c;查询游戏内角色相关信息&#xff0c;当时我也自己写了几个插件&#xff0c;也看到很多大佬编写的好玩的插件&#xff0c;后来因为QQ不…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

管理学院权限管理系统开发总结

文章目录 &#x1f393; 管理学院权限管理系统开发总结 - 现代化Web应用实践之路&#x1f4dd; 项目概述&#x1f3d7;️ 技术架构设计后端技术栈前端技术栈 &#x1f4a1; 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 &#x1f5c4;️ 数据库设…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

【Linux】Linux 系统默认的目录及作用说明

博主介绍&#xff1a;✌全网粉丝23W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

CppCon 2015 学习:Time Programming Fundamentals

Civil Time 公历时间 特点&#xff1a; 共 6 个字段&#xff1a; Year&#xff08;年&#xff09;Month&#xff08;月&#xff09;Day&#xff08;日&#xff09;Hour&#xff08;小时&#xff09;Minute&#xff08;分钟&#xff09;Second&#xff08;秒&#xff09; 表示…...

【记录坑点问题】IDEA运行:maven-resources-production:XX: OOM: Java heap space

问题&#xff1a;IDEA出现maven-resources-production:operation-service: java.lang.OutOfMemoryError: Java heap space 解决方案&#xff1a;将编译的堆内存增加一点 位置&#xff1a;设置setting-》构建菜单build-》编译器Complier...