Java 责任链模式详解
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它用于将请求的发送者和接收者解耦,使得多个对象都有机会处理这个请求。在责任链模式中,有一个请求处理链条,每个处理请求的对象都是一个节点,当请求进入这个链条时,链条上的节点逐一判断是否能够处理该请求,如果可以,则处理;否则,将请求传递给下一个节点,直到请求被处理为止。
责任链模式可以有效地避免请求发送者与接收者之间的耦合,将请求处理对象按照顺序串联起来形成一个链条,每个节点都可以根据自己的职责进行处理,可以动态地增加、删除或修改节点。责任链模式常用于处理请求的场景,例如登录验证、权限校验、日志记录、异常处理等。
本文将详细介绍 Java 中的责任链模式,包括其概念、结构、实现方式以及应用案例等,帮助读者更好地理解和应用责任链模式。
一、概念
责任链模式定义了一个请求处理对象的链条,每个对象都可以处理请求或者将请求转发给下一个对象,直到有一个对象处理请求为止。在责任链模式中,请求发送者不需要知道链条中具体的处理对象,只需要将请求发送给链头即可,具体的处理过程和实现细节由链条中的对象来决定。责任链模式可以有效地解耦请求发送者和接收者,分离职责,提高系统的灵活性和可维护性。
责任链模式包含以下几个角色:
- Handler(处理者):定义了处理请求的接口,通常包含一个抽象方法或者一个处理请求的抽象类。每个处理者都知道自己的后继者(下一个处理者),如果自己不能处理该请求,则将其转发给后继者。
- ConcreteHandler(具体处理者):实现了 Handler 接口,并对请求进行实际处理。每个具体处理者都能够处理一些特定的请求类型,如果自己不能处理该请求,则将其转发给后继者。
- Client(客户端):创建链条的起点,向链条头部的处理者发送请求。
二、结构
责任链模式的结构比较简单,主要包括以下几个部分:

其中,Handler 是一个抽象类或接口,定义了处理请求的方法 handleRequest() 和设置后继节点的方法 setSuccessor()。ConcreteHandler 类继承了 Handler 并实现了 handleRequest() 方法,在方法中判断是否能够处理该请求,如果能够处理则进行处理;否则将请求转发给下一个处理者。Client 类创建责任链的头部(即第一个 ConcreteHandler 对象),并向它发送请求。
三、实现方式
- 单向链表实现
单向链表是最常见的责任链模式实现方式,具有以下特点:
- 链表中节点的处理顺序与其添加顺序相同。
- 可以动态添加、删除或修改节点。
单向链表实现的核心代码如下:
public abstract class Handler {private Handler successor; // 后继节点public void setSuccessor(Handler successor) {this.successor = successor;}// 处理请求的抽象方法public abstract void handleRequest(Request request);protected void next(Request request) {if (successor != null) { // 如果有后继节点,则转发请求successor.handleRequest(request);}}
}public class ConcreteHandlerA extends Handler {@Overridepublic void handleRequest(Request request) {if (canHandle(request)) { // 判断是否能够处理该请求// 处理请求} else {next(request); // 转发请求给下一个处理者}}private boolean canHandle(Request request) {// 判断是否能够处理该请求的逻辑}
}public class Client {public static void main(String[] args) {Handler handlerA = new ConcreteHandlerA();Handler handlerB = new ConcreteHandlerB();handlerA.setSuccessor(handlerB); // 设置后继节点Request request = new Request();handlerA.handleRequest(request); // 发送请求到链头}
}
- 数组或队列实现
除了单向链表,还可以使用数组或队列等数据结构来实现责任链模式,主要思想是将处理者放在一个数组或队列中按序存储。这种实现方式比较简单,但不够灵活,并且不支持动态添加、删除或修改节点。
数组或队列实现的核心代码如下:
public abstract class Handler {// ...// 处理请求的抽象方法public abstract void handleRequest(Request request);protected void next(Request request, Handler[] handlers, int index) {if (index < handlers.length) { // 如果有后继节点,则转发请求handlers[index].handleRequest(request);}}
}public class Client {public static void main(String[] args) {Handler[] handlers = new Handler[] {new ConcreteHandlerA(), new ConcreteHandlerB()};Request request = new Request();handlers[0].handleRequest(request, handlers, 1); // 发送请求到链头}
}
四、应用案例
责任链模式在Java中有许多应用场景,例如:
-
过滤器(Filter):在Servlet中,过滤器就是使用责任链模式实现的。每个过滤器都可以决定是否处理请求,或者将其转发给下一个过滤器进行处理。
-
拦截器(Interceptor):在Spring框架中,拦截器就是使用责任链模式实现的。拦截器可以对请求进行预处理或后处理,也可以将请求转发给下一个拦截器进行处理。
-
异常处理(Exception Handling):在Java中,可以使用责任链模式来处理异常。首先,程序先尝试使用自定义的异常处理器来处理异常,如果该处理器无法处理异常,则将其转发给下一个处理器进行处理。
-
日志记录(Logger):在Java中,可以使用责任链模式来记录日志。每个日志记录器都可以决定是否需要记录该日志,或者将其转发给下一个日志记录器进行记录。
五、总结
责任链模式是一种常见的设计模式,在Java中有多种实现方式。通过责任链模式,可以将请求发送者和接收者解耦,提高系统的灵活性和可维护性。在实际应用中,可以将责任链模式应用于过滤器、拦截器、异常处理、日志记录等场景,从而实现统一的处理逻辑。
相关文章:
Java 责任链模式详解
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它用于将请求的发送者和接收者解耦,使得多个对象都有机会处理这个请求。在责任链模式中,有一个请求处理链条,每个处理请求的对象都是一个…...
使用MASA全家桶从零开始搭建IoT平台(三)管理设备的连接状态
文章目录 前言分析方案1:遗嘱消息演示遗嘱消息的使用实施流程 方案2:使用WebHook开启WebHook演示Webhook编写代码 前言 获取一个设备的在线和离线状态,是一个很关键的功能。我们对设备下发的控制指令,设备处于在线状态才能及时给我们反馈。这里的在线和…...
我的新书上架了!
talk is cheap,show you my book! 新书《从0开始学ARM》终于在各大平台上架了!! 一、关于本书 1. 本书主要内容 ARM体系架构是目前市面上的主流处理器体系架构,在手机芯片和嵌入式芯片领域,ARM体系架构…...
语言与专业的奇迹:如何利用ChatGPT优化跨国贸易
贸易公司,在进行跨国贸易时,往往需要面对不同国家的甲方或者乙方,在与之沟通的过程中,语言和专业是必须要过的一关,顺畅的交流,往往会带来更好的收益。 今天以“茶”为例,给大家介绍一“知否AI…...
云服务器安装宝塔Linux面板命令脚本大全
阿里云服务器安装宝塔Linux面板,操作系统不同安装命令脚本也不同,支持CentOS、Alibaba Cloud Linux、Ubuntu/Deepin等Linux系统,阿里云服务器网分享阿里云服务器安装宝塔Linux面板命令脚本大全: 云服务器安装宝塔Linux面板命令 …...
zed2i相机中imu内参的标定及外参标定
zed2i中imu内参的标定 参考: https://blog.csdn.net/weixin_42681311/article/details/126109617 https://blog.csdn.net/weixin_43135184/article/details/123444090 值得注意,imu内参的标定其实不是那么重要,大致上给一个值应该影响不大…...
Java中的JUnit是什么?如何使用JUnit进行单元测试
JUnit是Java中最流行的单元测试框架之一。它可以帮助开发人员在代码编写过程中检测出错误和异常,从而提高代码的质量和可靠性。 什么是JUnit? JUnit是一个由Kent Beck和Erich Gamma创建的开源Java单元测试框架,它已经成为Java开发中最常用的…...
【seata的部署和集成】
seata的部署和集成 seata的部署和集成一、部署Seata的tc-server1.下载2.解压3.修改配置4.在nacos添加配置5.创建数据库表6.启动TC服务 二、微服务集成seata1.引入依赖2.修改配置文件 三、TC服务的高可用和异地容灾1.模拟异地容灾的TC集群2.将事务组映射配置到nacos3.微服务读取…...
uniapp学习日记之request自定义请求头
uniapp学习日记之request自定义请求头 在学习uniapp的过程中,由于笔者是从Vue项目转来学习uniapp,在使用uni.request时,发现在浏览器调试时,无法在请求头header中添加token字段,愤而弃之,便开始使用axios组…...
【Rust】速度入门---打印个螃蟹先
参考: 菜鸟教程 1 输出到命令行 这不得打印个螃蟹 // 代码来自官方入门教程 // ferris_say需要另外安装 use ferris_says::say; use std::io::{stdout, BufWriter};fn main() {let stdout: std::io::Stdout stdout();let msg: String String::from("Hello fellow Rusta…...
《Linux 内核设计与实现》12. 内存管理
文章目录 页区获得页获得填充为 0 的页释放页 kmalloc()gfp_mask 标志kfree()vmalloc() slab 层slab 层的设计slab 分配器的接口 在栈上的静态分配单页内核栈 高端内存的映射永久映射临时映射 每个 CPU 的分配新的每个 CPU 接口 页 struct page 结构表示系统中的物理页&#x…...
公司新来个卷王,让人崩溃...
最近内卷严重,各种跳槽裁员,相信很多小伙伴也在准备今年的面试计划。 在此展示一套学习笔记 / 面试手册,年后跳槽的朋友可以好好刷一刷,还是挺有必要的,它几乎涵盖了所有的软件测试技术栈,非常珍贵&#x…...
Docker 安全及日志管理
Docker 安全及日志管理 Docker 容器与虚拟机的区别隔离与共享性能与损耗 Docker 存在的安全问题Docker 自身漏洞Docker 源码问题Docker 架构缺陷与安全机制Docker 安全基线标准 容器相关的常用安全配置方法容器最小化Docker 远程 API 访问控制重启 Docker在宿主机的 firewalld …...
大厂面试必备 - MAC 地址 和 IP 地址分别有什么作用?
数据链路层 1、MAC 地址 和 IP 地址分别有什么作用? MAC 地址是数据链路层和物理层使用的地址,是写在网卡上的物理地址。MAC 地址用来定义网络设备的位置。IP 地址是网络层和以上各层使用的地址,是一种逻辑地址。IP 地址用来区别网络上的计…...
【sqlite】联查Join更新
系列文章 C#底层库–MySQLBuilder脚本构建类(select、insert、update、in、带条件的SQL自动生成) 本文链接:https://blog.csdn.net/youcheng_ge/article/details/129179216 C#底层库–MySQL数据库操作辅助类(推荐阅读࿰…...
asp.net+C#德育课程分数统计管理系统
本中小学德育管理系统主要学校内部提供服务,系统分为管理员,教师和学生3个大模块。 本研究课题重点主要包括了下面几大模块:用户登录,管理员信息管理学生信息管理,教师信息管理,班级成绩管理,学…...
Figma中文网?比Figma更懂你的设计网站!
一个比 Figma 更懂你的设计网站的 Figma 中文网 —— 即时设计是一个非常有用的设计资源平台,它提供了大量的免费设计素材,包括来自各大厂商的 UI 组件库、精美的模板、插画设计和矢量图标素材等等。设计师可以从中学习到大师的设计技巧和规范࿰…...
Nacos-01-Nacos基本介绍
背景 服务发现是⼀个古老的话题,当应用开始脱离单机运行和访问时,服务发现就诞生了。目前的网络架构是每个主机都有⼀个独立的 IP 地址,那么服务发现基本上都是通过某种方式获取到服务所部署的 IP 地址。DNS 协议是最早将⼀个网络名称翻译…...
SpringBoot集成Dubbo启用gRPC协议
文章目录 前言项目结构代码示例父工程api moduleservice module 注意事项区别 本文记录下SpringBoot集成Dubbo启用gRPC协议,以及与原生 gRPC 在代码编写过程中的区别。 下面还有投票,帮忙投个票👍 前言 Dubbo 在 2.7.5 版本开始支持原生 gRP…...
Kali HTTrack演示-渗透测试察打一体(1)
HTTrack是一个免费并易于使用的线下浏览器工具,全称是HTTrack Website Copier for Windows,它能够让你从互联网上下载指定的网站进行线下浏览(离线浏览),也可以用来收集信息(甚至有网站使用隐藏的密码文件),一些仿真度极高的伪网站(为了骗取用户密码),也是使用类似工具做…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
土建施工员考试:建筑施工技术重点知识有哪些?
《管理实务》是土建施工员考试中侧重实操应用与管理能力的科目,核心考查施工组织、质量安全、进度成本等现场管理要点。以下是结合考试大纲与高频考点整理的重点内容,附学习方向和应试技巧: 一、施工组织与进度管理 核心目标: 规…...
[特殊字符] 手撸 Redis 互斥锁那些坑
📖 手撸 Redis 互斥锁那些坑 最近搞业务遇到高并发下同一个 key 的互斥操作,想实现分布式环境下的互斥锁。于是私下顺手手撸了个基于 Redis 的简单互斥锁,也顺便跟 Redisson 的 RLock 机制对比了下,记录一波,别踩我踩过…...
从实验室到产业:IndexTTS 在六大核心场景的落地实践
一、内容创作:重构数字内容生产范式 在短视频创作领域,IndexTTS 的语音克隆技术彻底改变了配音流程。B 站 UP 主通过 5 秒参考音频即可克隆出郭老师音色,生成的 “各位吴彦祖们大家好” 语音相似度达 97%,单条视频播放量突破百万…...
背包问题双雄:01 背包与完全背包详解(Java 实现)
一、背包问题概述 背包问题是动态规划领域的经典问题,其核心在于如何在有限容量的背包中选择物品,使得总价值最大化。根据物品选择规则的不同,主要分为两类: 01 背包:每件物品最多选 1 次(选或不选&#…...
高保真组件库:开关
一:制作关状态 拖入一个矩形作为关闭的底色:44 x 22,填充灰色CCCCCC,圆角23,边框宽度0,文本为”关“,右对齐,边距2,2,6,2,文本颜色白色FFFFFF。 拖拽一个椭圆,尺寸18 x 18,边框为0。3. 全选转为动态面板状态1命名为”关“。 二:制作开状态 复制关状态并命名为”开…...
欢乐熊大话蓝牙知识17:多连接 BLE 怎么设计服务不会乱?分层思维来救场!
多连接 BLE 怎么设计服务不会乱?分层思维来救场! 作者按: 你是不是也遇到过 BLE 多连接时,调试现场像网吧“掉线风暴”? 温度传感器连上了,心率带丢了;一边 OTA 更新,一边通知卡壳。…...
使用ch340继电器完成随机断电测试
前言 如图所示是市面上常见的OTA压测继电器,通过ch340串口模块完成对继电器的分路控制,这里我编写了一个脚本方便对4路继电器的控制,可以设置开启时间,关闭时间,复位等功能 软件界面 在设备管理器查看串口号后&…...
