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,它能够让你从互联网上下载指定的网站进行线下浏览(离线浏览),也可以用来收集信息(甚至有网站使用隐藏的密码文件),一些仿真度极高的伪网站(为了骗取用户密码),也是使用类似工具做…...

国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...
【FTP】ftp文件传输会丢包吗?批量几百个文件传输,有一些文件没有传输完整,如何解决?
FTP(File Transfer Protocol)本身是一个基于 TCP 的协议,理论上不会丢包。但 FTP 文件传输过程中仍可能出现文件不完整、丢失或损坏的情况,主要原因包括: ✅ 一、FTP传输可能“丢包”或文件不完整的原因 原因描述网络…...

macOS 终端智能代理检测
🧠 终端智能代理检测:自动判断是否需要设置代理访问 GitHub 在开发中,使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新,例如: fatal: unable to access https://github.com/ohmyzsh/oh…...