Java设计模式:责任链模式
一、什么是责任链模式?
责任链模式(Chain of Responsibility Pattern) 是一种 行为型设计模式,它通过将请求沿着一条处理链传递,直到某个对象处理它为止。这种模式的核心思想是 解耦请求的发送者和接收者,使多个对象都有机会处理请求,避免请求发送者与具体处理者之间的紧耦合。
核心角色
-
抽象处理者(Handler)
- 定义处理请求的接口,包含一个指向下一个处理者的引用(
nextHandler
)。 - 提供设置后续处理者的方法(
setNextHandler
),用于构建责任链。
- 定义处理请求的接口,包含一个指向下一个处理者的引用(
-
具体处理者(ConcreteHandler)
- 实现抽象处理者的处理方法,判断自己是否有权限处理请求:
- 若有权,处理请求并结束流程;
- 若无权,将请求传递给后续处理者(
nextHandler.handleRequest
)。
- 实现抽象处理者的处理方法,判断自己是否有权限处理请求:
-
客户端(Client)
- 创建责任链,并向链的起点发送请求,无需知道具体是哪个处理者处理了请求。
二、责任链模式的核心思想
责任链模式的核心是 “链式传递” 和 “责任分配” 的分离。
- 链式传递:请求从链的起点开始,依次传递给每个处理者,直到某个处理者处理它。
- 责任分配:每个处理者只负责自己职责范围内的请求,超出范围的请求则传递给下一个处理者。
生活中的例子
想象你在公司提交一个报销申请,流程如下:
- 直接主管审批(1000元以下);
- 部门经理审批(1000-5000元);
- 财务总监审批(5000元以上)。
这就是一个典型的责任链模式,每个审批人只处理自己权限范围内的请求,超出权限则传递给下一个审批人。
三、Java实现责任链模式
1. 基础示例:请假审批系统
(1)定义抽象处理者
// 抽象处理者类:定义了处理请求的接口和设置下一个处理者的方法
public abstract class LeaveHandler {// 持有下一个处理者的引用,形成链式结构protected LeaveHandler nextHandler;// 设置下一个处理者public void setNextHandler(LeaveHandler nextHandler) {this.nextHandler = nextHandler;}// 抽象方法:具体处理者需要实现该方法来处理请求public abstract void handleRequest(LeaveRequest request);
}
(2)定义具体处理者
// 具体处理者:小组长,处理1-3天的请假请求
public class TeamLeader extends LeaveHandler {@Overridepublic void handleRequest(LeaveRequest request) {// 判断是否在自己的处理范围内if (request.getDays() <= 3) {System.out.println("小组长批准了 " + request.getName() + " 的 " + request.getDays() + " 天请假");} else if (nextHandler != null) {// 超出处理范围且存在下一个处理者,将请求传递nextHandler.handleRequest(request);} else {// 没有合适的处理者System.out.println("无人能处理该请求");}}
}// 具体处理者:经理,处理3-7天的请假请求
public class Manager extends LeaveHandler {@Overridepublic void handleRequest(LeaveRequest request) {// 判断是否在自己的处理范围内if (request.getDays() <= 7) {System.out.println("经理批准了 " + request.getName() + " 的 " + request.getDays() + " 天请假");} else if (nextHandler != null) {// 超出处理范围且存在下一个处理者,将请求传递nextHandler.handleRequest(request);} else {// 没有合适的处理者System.out.println("无人能处理该请求");}}
}// 具体处理者:总监,处理7天以上的请假请求
public class Director extends LeaveHandler {@Overridepublic void handleRequest(LeaveRequest request) {// 判断是否在自己的处理范围内if (request.getDays() > 7) {System.out.println("总监批准了 " + request.getName() + " 的 " + request.getDays() + " 天请假");} else if (nextHandler != null) {// 超出处理范围且存在下一个处理者,将请求传递nextHandler.handleRequest(request);} else {// 没有合适的处理者System.out.println("无人能处理该请求");}}
}
(3)定义请求类
// 请假请求类:封装了请假的相关信息
public class LeaveRequest {private String name; // 请假人姓名private int days; // 请假天数private String reason; // 请假原因public LeaveRequest(String name, int days, String reason) {this.name = name;this.days = days;this.reason = reason;}// 以下是获取请假信息的方法public String getName() { return name; }public int getDays() { return days; }public String getReason() { return reason; }
}
(4)客户端调用
// 客户端类:构建责任链并提交请求
public class Client {public static void main(String[] args) {// 1. 构建责任链:按照 小组长 -> 经理 -> 总监 的顺序设置LeaveHandler teamLeader = new TeamLeader();LeaveHandler manager = new Manager();LeaveHandler director = new Director();// 设置责任链顺序teamLeader.setNextHandler(manager);manager.setNextHandler(director);// 2. 创建请假请求LeaveRequest request1 = new LeaveRequest("张三", 2, "生病"); // 2天请假,应由小组长处理LeaveRequest request2 = new LeaveRequest("李四", 10, "家庭事务"); // 10天请假,应由总监处理// 3. 提交请求到责任链的起点(小组长)// 当调用 teamLeader.handleRequest(request1) 时:// - 小组长判断2天 <=3天,直接处理该请求teamLeader.handleRequest(request1);// 当调用 teamLeader.handleRequest(request2) 时:// - 小组长判断10天 >3天,将请求传递给经理// - 经理判断10天 >7天,将请求传递给总监// - 总监判断10天 >7天,处理该请求teamLeader.handleRequest(request2);}
}
⑸、流程图和内存图
2.责任链模式的经典实现
下面通过一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限:
(1)定义抽象处理者
// Approver.java
public abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者public void setSuccessor(Approver successor) {this.successor = successor;}// 处理请求的抽象方法public abstract void processRequest(PurchaseRequest request);
}
(2)定义具体处理者
// Director.java
public class Director extends Approver {@Overridepublic void processRequest(PurchaseRequest request) {if (request.getAmount() < 10000) {System.out.println("主任审批了金额为 " + request.getAmount() + " 的采购申请");} else if (successor != null) {successor.processRequest(request);}}
}
// Manager.java
public class Manager extends Approver {@Overridepublic void processRequest(PurchaseRequest request) {if (request.getAmount() < 50000) {System.out.println("经理审批了金额为 " + request.getAmount() + " 的采购申请");} else if (successor != null) {successor.processRequest(request);}}
}
// VicePresident.java
public class VicePresident extends Approver {@Overridepublic void processRequest(PurchaseRequest request) {if (request.getAmount() < 100000) {System.out.println("副总裁审批了金额为 " + request.getAmount() + " 的采购申请");} else if (successor != null) {successor.processRequest(request);}}
}
// President.java
public class President extends Approver {@Overridepublic void processRequest(PurchaseRequest request) {if (request.getAmount() < 500000) {System.out.println("总裁审批了金额为 " + request.getAmount() + " 的采购申请");} else {System.out.println("金额过大,需要董事会讨论");}}
}
(3)定义请求类
// PurchaseRequest.java
public class PurchaseRequest {private double amount; // 金额private String purpose; // 用途public PurchaseRequest(double amount, String purpose) {this.amount = amount;this.purpose = purpose;}public double getAmount() {return amount;}public String getPurpose() {return purpose;}
}
(4)客户端调用
// Client.java
public class Client {public static void main(String[] args) {// 创建处理者Approver director = new Director();Approver manager = new Manager();Approver vicePresident = new VicePresident();Approver president = new President();// 设置责任链director.setSuccessor(manager);manager.setSuccessor(vicePresident);vicePresident.setSuccessor(president);// 创建采购申请PurchaseRequest request1 = new PurchaseRequest(5000, "购买办公用品");PurchaseRequest request2 = new PurchaseRequest(30000, "购买电脑设备");PurchaseRequest request3 = new PurchaseRequest(80000, "购买服务器");PurchaseRequest request4 = new PurchaseRequest(300000, "购买办公大楼");// 处理请求director.processRequest(request1);director.processRequest(request2);director.processRequest(request3);director.processRequest(request4);}
}
在这个示例中,我们创建了一个审批链,从主任到经理、副总裁,最后到总裁。每个审批者根据自己的权限处理请求,如果无法处理则将请求传递给下一个审批者。客户端只需要将请求发送给链头的处理者,无需关心具体是哪个处理者最终处理了请求。
能不能连写?return this;返回的是谁
四、责任链模式在 Java 中的实际应用
责任链模式在 Java 中有许多实际应用场景,例如:
- Servlet 过滤器链:在 Java Web 应用中,Servlet 过滤器可以形成一个链,每个过滤器负责特定的任务,如编码转换、权限验证等。
- 日志记录系统:不同级别的日志可以由不同的处理器处理,如控制台日志、文件日志、数据库日志等。
- 异常处理链:多个异常处理器可以按顺序尝试处理异常。
下面是一个使用 Java 8 函数式编程简化责任链模式的示例:
import java.util.function.Consumer;public class FunctionalChainExample {public static void main(String[] args) {// 定义处理者Consumer<String> logger = message -> System.out.println("日志记录: " + message);Consumer<String> authChecker = message -> {if (message.contains("admin")) {System.out.println("权限验证通过");} else {System.out.println("权限验证失败");}};Consumer<String> processor = message -> System.out.println("处理请求: " + message);// 构建责任链Consumer<String> chain = logger.andThen(authChecker).andThen(processor);// 处理请求chain.accept("admin:create_user");chain.accept("user:view_profile");}
}
这个示例使用 Java 8 的函数式接口和方法引用简化了责任链的实现,使代码更加简洁和灵活。
责任链模式的优缺点
优点:
- 降低了请求发送者和接收者之间的耦合度。
- 可以动态添加或修改处理者,提高了系统的灵活性。
- 简化了对象间的连接,每个对象只需保持一个后续者引用。
缺点:
- 请求可能无法被处理,因为链中没有合适的处理者。
- 如果责任链过长,可能会影响系统性能。
- 调试时可能会比较困难,因为请求的处理过程是隐式的。
总结
责任链模式是一种非常实用的设计模式,它将请求的发送者和接收者解耦,使多个处理者都有机会处理请求。通过合理地使用责任链模式,可以提高系统的灵活性和可维护性。在实际开发中,我们可以根据具体需求选择传统的实现方式或使用函数式编程进行简化。无论是 Servlet 过滤器链还是日志处理系统,责任链模式都能发挥其独特的优势。
相关文章:

Java设计模式:责任链模式
一、什么是责任链模式? 责任链模式(Chain of Responsibility Pattern) 是一种 行为型设计模式,它通过将请求沿着一条处理链传递,直到某个对象处理它为止。这种模式的核心思想是 解耦请求的发送者和接收者,…...
比特币:固若金汤的数字堡垒与它的四道防线
第一道防线:机密信函——无法破解的哈希加密 将每一笔比特币交易比作一封在堡垒内部传递的机密信函。 解释“哈希”(Hashing)就是一种军事级的加密术(SHA-256),能将信函内容(交易细节…...
基于 HTTP 的单向流式通信协议SSE详解
SSE(Server-Sent Events)详解 🧠 什么是 SSE? SSE(Server-Sent Events) 是 HTML5 标准中定义的一种通信机制,它允许服务器主动将事件推送给客户端(浏览器)。与传统的 H…...

初探用uniapp写微信小程序遇到的问题及解决(vue3+ts)
零、关于开发思路 (一)拿到工作任务,先理清楚需求 1.逻辑部分 不放过原型里说的每一句话,有疑惑的部分该问产品/测试/之前的开发就问 2.页面部分(含国际化) 整体看过需要开发页面的原型后,分类一下哪些组件/样式可以复用,直接提取出来使用 (时间充分的前提下,不…...
接口 RESTful 中的超媒体:REST 架构的灵魂驱动
在 RESTful 架构中,** 超媒体(Hypermedia)** 是一个核心概念,它体现了 REST 的 “表述性状态转移(Representational State Transfer)” 的本质,也是区分 “真 RESTful API” 与 “伪 RESTful AP…...
第22节 Node.js JXcore 打包
Node.js是一个开放源代码、跨平台的、用于服务器端和网络应用的运行环境。 JXcore是一个支持多线程的 Node.js 发行版本,基本不需要对你现有的代码做任何改动就可以直接线程安全地以多线程运行。 本文主要介绍JXcore的打包功能。 JXcore 安装 下载JXcore安装包&a…...

云原生时代的系统设计:架构转型的战略支点
📝个人主页🌹:一ge科研小菜鸡-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、云原生的崛起:技术趋势与现实需求的交汇 随着企业业务的互联网化、全球化、智能化持续加深,传统的 I…...
Git 命令全流程总结
以下是从初始化到版本控制、查看记录、撤回操作的 Git 命令全流程总结,按操作场景分类整理: 一、初始化与基础操作 操作命令初始化仓库git init添加所有文件到暂存区git add .提交到本地仓库git commit -m "提交描述"首次提交需配置身份git c…...

python可视化:俄乌战争时间线关键节点与深层原因
俄乌战争时间线可视化分析:关键节点与深层原因 俄乌战争是21世纪欧洲最具影响力的地缘政治冲突之一,自2022年2月爆发以来已持续超过3年。 本文将通过Python可视化工具,系统分析这场战争的时间线、关键节点及其背后的深层原因,全面…...

C# WPF 左右布局实现学习笔记(1)
开发流程视频: https://www.youtube.com/watch?vCkHyDYeImjY&ab_channelC%23DesignPro Git源码: GitHub - CSharpDesignPro/Page-Navigation-using-MVVM: WPF - Page Navigation using MVVM 1. 新建工程 新建WPF应用(.NET Framework) 2.…...

Linux入门(十五)安装java安装tomcat安装dotnet安装mysql
安装java yum install java-17-openjdk-devel查找安装地址 update-alternatives --config java设置环境变量 vi /etc/profile #在文档后面追加 JAVA_HOME"通过查找安装地址命令显示的路径" #注意一定要加$PATH不然路径就只剩下新加的路径了,系统很多命…...

【QT控件】显示类控件
目录 一、Label 二、LCD Number 三、ProgressBar 四、Calendar Widget QT专栏:QT_uyeonashi的博客-CSDN博客 一、Label QLabel 可以用来显示文本和图片. 核心属性如下 代码示例: 显示不同格式的文本 1) 在界面上创建三个 QLabel 尺寸放大一些. objectName 分别…...
使用python进行图像处理—图像滤波(5)
图像滤波是图像处理中最基本和最重要的操作之一。它的目的是在空间域上修改图像的像素值,以达到平滑(去噪)、锐化、边缘检测等效果。滤波通常通过卷积操作实现。 5.1卷积(Convolution)原理 卷积是滤波的核心。它是一种数学运算,…...

npm安装electron下载太慢,导致报错
npm安装electron下载太慢,导致报错 背景 想学习electron框架做个桌面应用,卡在了安装依赖(无语了)。。。一开始以为node版本或者npm版本太低问题,调整版本后还是报错。偶尔执行install命令后,可以开始下载…...

职坐标物联网全栈开发全流程解析
物联网全栈开发涵盖从物理设备到上层应用的完整技术链路,其核心流程可归纳为四大模块:感知层数据采集、网络层协议交互、平台层资源管理及应用层功能实现。每个模块的技术选型与实现方式直接影响系统性能与扩展性,例如传感器选型需平衡精度与…...
6.9本日总结
一、英语 复习默写list11list18,订正07年第3篇阅读 二、数学 学习线代第一讲,写15讲课后题 三、408 学习计组第二章,写计组习题 四、总结 明天结束线代第一章和计组第二章 五、明日计划 英语:复习l默写sit12list17&#…...
RLHF vs RLVR:对齐学习中的两种强化方式详解
在语言模型对齐(alignment)中,强化学习(RL)是一种重要的策略。而其中两种典型形式——RLHF(Reinforcement Learning with Human Feedback) 与 RLVR(Reinforcement Learning with Ver…...
OpenGL-什么是软OpenGL/软渲染/软光栅?
软OpenGL(Software OpenGL)或者软渲染指完全通过CPU模拟实现的OpenGL渲染方式(包括几何处理、光栅化、着色等),不依赖GPU硬件加速。这种模式通常性能较低,但兼容性极强,常用于不支持硬件加速…...

【工具教程】多个条形码识别用条码内容对图片重命名,批量PDF条形码识别后用条码内容批量改名,使用教程及注意事项
一、条形码识别改名使用教程 打开软件并选择处理模式:打开软件后,根据要处理的文件类型,选择 “图片识别模式” 或 “PDF 识别模式”。如果是处理包含条形码的 PDF 文件,就选择 “PDF 识别模式”;若是处理图片文件&…...

英国云服务器上安装宝塔面板(BT Panel)
在英国云服务器上安装宝塔面板(BT Panel) 是完全可行的,尤其适合需要远程管理Linux服务器、快速部署网站、数据库、FTP、SSL证书等服务的用户。宝塔面板以其可视化操作界面和强大的功能广受国内用户欢迎,虽然官方主要面向中国大陆…...

数据挖掘是什么?数据挖掘技术有哪些?
目录 一、数据挖掘是什么 二、常见的数据挖掘技术 1. 关联规则挖掘 2. 分类算法 3. 聚类分析 4. 回归分析 三、数据挖掘的应用领域 1. 商业领域 2. 医疗领域 3. 金融领域 4. 其他领域 四、数据挖掘面临的挑战和未来趋势 1. 面临的挑战 2. 未来趋势 五、总结 数据…...
Cursor AI 账号纯净度维护与高效注册指南
Cursor AI 账号纯净度维护与高效注册指南:解决限制问题的实战方案 风车无限免费邮箱系统网页端使用说明|快速获取邮箱|cursor|windsurf|augment 问题背景 在成功解决 Cursor 环境配置问题后,许多开发者仍面临账号纯净度不足导致的限制问题。无论使用 16…...
用 FFmpeg 实现 RTMP 推流直播
RTMP(Real-Time Messaging Protocol) 是直播行业中常用的传输协议。 一般来说,直播服务商会给你: ✅ 一个 RTMP 推流地址(你推视频上去) ✅ 一个 HLS 或 FLV 拉流地址(观众观看用)…...

简约商务通用宣传年终总结12套PPT模版分享
IOS风格企业宣传PPT模版,年终工作总结PPT模版,简约精致扁平化商务通用动画PPT模版,素雅商务PPT模版 简约商务通用宣传年终总结12套PPT模版分享:商务通用年终总结类PPT模版https://pan.quark.cn/s/ece1e252d7df...
P10909 [蓝桥杯 2024 国 B] 立定跳远
# P10909 [蓝桥杯 2024 国 B] 立定跳远 ## 题目描述 在运动会上,小明从数轴的原点开始向正方向立定跳远。项目设置了 $n$ 个检查点 $a_1, a_2, \cdots , a_n$ 且 $a_i \ge a_{i−1} > 0$。小明必须先后跳跃到每个检查点上且只能跳跃到检查点上。同时࿰…...

【Qt】控件 QWidget
控件 QWidget 一. 控件概述二. QWidget 的核心属性可用状态:enabled几何:geometrywindows frame 窗口框架的影响 窗口标题:windowTitle窗口图标:windowIconqrc 机制 窗口不透明度:windowOpacity光标:cursor…...

Linux入门课的思维导图
耗时两周,终于把慕课网上的Linux的基础入门课实操、总结完了! 第一次以Blog的形式做学习记录,过程很有意思,但也很耗时。 课程时长5h,涉及到很多专有名词,要去逐个查找,以前接触过的概念因为时…...

aurora与pcie的数据高速传输
设备:zynq7100; 开发环境:window; vivado版本:2021.1; 引言 之前在前面两章已经介绍了aurora读写DDR,xdma读写ddr实验。这次我们做一个大工程,pc通过pcie传输给fpga,fpga再通过aur…...

Springboot 高校报修与互助平台小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,高校报修与互助平台小程序被用户普遍使用,为…...

Linux 内存管理调试分析:ftrace、perf、crash 的系统化使用
Linux 内存管理调试分析:ftrace、perf、crash 的系统化使用 Linux 内核内存管理是构成整个内核性能和系统稳定性的基础,但这一子系统结构复杂,常常有设置失败、性能展示不良、OOM 杀进程等问题。要分析这些问题,需要一套工具化、…...