Java设计模式 —— 【行为型模式】责任链模式(Chain-of-responsibility Pattern) 详解
文章目录
- 模式介绍
- 优缺点
- 适用场景
- 模式结构
- 案例实现
模式介绍
责任链模式又名职责链模式,它是一种对象行为的设计模式,为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。职责链可以是一条直线、一个环链或者是一个树结构的一部分。
在现实生活中,常常会出现这样的事例:一个请求有多个对象可以处理,但每个对象的处理条件或权限不同。例如,公司员工请假,可批假的领导有部门负责人、副总经理、总经理等,但每个领导能批准的天数不同,员工必须根据自己要请假的天数去找不同的领导签名,也就是说员工必须记住每个领导的姓名、电话和地址等信息,这增加了难度。这样的例子还有很多,如找领导出差报销、生活中的“击鼓传花”游戏等。但是使用责任链一级一级传递就会方便很多。
优缺点
1、优点:
- 降低了对象之间的耦合度: 该模式降低了请求发送者和接收者的耦合度;
- 增强了系统的可扩展性: 可以根据需要增加新的请求处理类,满足开闭原则;
- 增强了给对象指派职责的灵活性: 当工作流程发生变化,可以动态地改变链内的成员或者修改它们的次序,也可动态地新增或者删除责任;
- 责任链简化了对象之间的连接: 一个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的
if或者if···else...语句; - 责任分担: 每个类只需要处理自己该处理的工作,不能处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
2、缺点:
- 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理;
- 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响;
- 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。
适用场景
- 有多个对象可以处理一个请求,哪个对象处理该请求由运行时刻自动确定;
- 可动态指定一组对象处理请求,或添加新的处理者;
- 在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求。
模式结构
职责链模式主要包含以下角色:
- 抽象处理者(
Handler)角色: 定义一个处理请求的接口,包含抽象处理方法和一个后继连接; - 具体处理者(
Concrete Handler)角色: 实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者; - 客户类(
Client)角色: 创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程;

案例实现
现需要开发一个请假流程控制系统。请假1天的只需要小组长同意即可;请假1天到3天的还需要部门经理同意;请求3天到7天还需要总经理同意才行。
UML类图如下:

抽象处理者角色:
public abstract class Handler {protected final static int NUM_ONE = 1;protected final static int NUM_THREE = 3;protected final static int NUM_SEVEN = 7;//该领导处理的请假天数区间private int numStart;private int numEnd;//领导上面还有领导private Handler nextHandler;//设置请假天数范围public Handler(int numStart) {this.numStart = numStart;}//设置请假天数范围public Handler(int numStart, int numEnd) {this.numStart = numStart;this.numEnd = numEnd;}//设置上级领导public void setNextHandler(Handler nextHandler){this.nextHandler = nextHandler;}//各级领导处理请假条方法protected abstract void handleLeave(LeaveRequest leave);//提交请假条public final void submit(LeaveRequest leave){//该领导审批this.handleLeave(leave);if (this.nextHandler != null && leave.getNum() > this.numEnd){//提交给上级领导this.nextHandler.submit(leave);} else {System.out.println("流程结束!");}}
}
具体处理者角色【组长、部门经理、总经理】:
public class GroupLeader extends Handler{public GroupLeader() {super(0, Handler.NUM_ONE);}@Overrideprotected void handleLeave(LeaveRequest leave) {System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");System.out.println("小组长审批:同意。");}
}
public class Manager extends Handler{public Manager() {super(Handler.NUM_ONE, Handler.NUM_THREE);}@Overrideprotected void handleLeave(LeaveRequest leave) {System.out.println("部门经理审批:同意。");}
}
public class GeneralManager extends Handler{public GeneralManager() {super(Handler.NUM_THREE, Handler.NUM_SEVEN);}@Overrideprotected void handleLeave(LeaveRequest leave) {System.out.println("总经理审批:同意。");}
}
请求【请假条】:
public class LeaveRequest {private String name;//姓名private int num;//请假天数private String content;//请假内容public LeaveRequest(String name, int num, String content) {this.name = name;this.num = num;this.content = content;}public String getName() {return name;}public int getNum() {return num;}public String getContent() {return content;}
}
测试:
public class Client {public static void main(String[] args) {GroupLeader groupLeader = new GroupLeader();Manager manager = new Manager();GeneralManager generalManager = new GeneralManager();groupLeader.setNextHandler(manager);manager.setNextHandler(generalManager);LeaveRequest leaveRequest1 = new LeaveRequest("张三", 1, "学习责任链模式");groupLeader.submit(leaveRequest1);System.out.println("=====================================");LeaveRequest leaveRequest2 = new LeaveRequest("张三", 3, "学习责任链模式");groupLeader.submit(leaveRequest2);System.out.println("=====================================");LeaveRequest leaveRequest3 = new LeaveRequest("张三", 7, "学习责任链模式");groupLeader.submit(leaveRequest3);}
}

相关文章:
Java设计模式 —— 【行为型模式】责任链模式(Chain-of-responsibility Pattern) 详解
文章目录 模式介绍优缺点适用场景模式结构案例实现 模式介绍 责任链模式又名职责链模式,它是一种对象行为的设计模式,为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链&…...
C++和Python中负数取余结果的区别
C中的负数取余规则(取模%)规则 在C中,取余运算( % )的结果符号与被除数相同。从数学定义角度看,C遵循的是尽量让商向零取整的规则。例如计算 -7/3,商是 -2 (向零取整)&a…...
rust学习——环境搭建
rust安装:https://kaisery.github.io/trpl-zh-cn/ch01-01-installation.html 1、vscode装插件: toml语法支持 依赖管理 rust语法支持 2、创建demo 3、查看目录 4、执行文件的几种方式: rust安装:https://www.rust-lang.org/z…...
Linux系统中解决端口占用问题
在日常的 Linux 系统管理和开发过程中,端口占用是一个常见且令人头疼的问题。无论是部署新服务、调试应用程序,还是进行系统维护,遇到端口被占用都可能导致服务无法正常启动或运行。本文将详细介绍在 Linux 系统中如何识别和解决端口占用问题…...
现代软件架构设计:14个质量属性的定义、权衡与最佳实践
1. 引言 1.1 技术架构的重要性 技术架构是指导软件系统设计和开发的核心,它定义了系统的高层结构及关键技术选型。一个优秀的技术架构可以提高开发效率、系统稳定性和扩展能力,确保项目成功落地。面对复杂业务场景,技术架构的设计至关重要&…...
【UE5 C++课程系列笔记】25——多线程基础——FGraphEventRef的简单使用
目录 概念 使用示例1 使用示例2 概念 FGraphEventRef 本质上是对一个异步任务或者一组相关异步任务在虚幻引擎任务图系统中的一种引用(reference)。虚幻引擎的任务图系统用于高效地调度和管理各种异步任务,协调它们的执行顺序以及处理任务…...
计算机网络之---信号与编码
信号 在物理层,信号是用来传输比特流的物理量,它可以是电压、电流、光强度等形式,通常通过电缆、光纤或者无线信道等媒介传播。 信号主要分为以下两种类型: 模拟信号(Analog Signal):信号在时间…...
linux下用命令行给串口写数据和读数据
在 Linux 系统中,串口设备(如 /dev/ttyS3)可以通过命令行进行读写操作。您遇到的问题是因为 Bash 解释了命令行中的字符串 “dis vlan\n”,但并没有按预期向串口设备发送数据。你应该将数据通过重定向发送到串口设备。 下面是如何…...
【生物信息】如何使用 h5py 读取 HDF5 格式文件中的数据并将其转换为 NumPy 数组
data_mat h5py.File(args.data_file) x1 np.array(data_mat[X1]) x2 np.array(data_mat[X2]) if not args.no_labels: y np.array(data_mat[Y]) data_mat.close() 这段代码展示了如何使用 h5py 读取 HDF5 格式文件中的数据并将其转换为 NumPy 数组。以下是代码的详细解释&a…...
纯手工(不基于maven的pom.xml、Web容器)连接MySQL数据库的详细过程(Java Web学习笔记)
1 引言 最近读一些Java Web开发类的书籍时,发现书中的连接数据库的过程缺少了一些关键性的过程,这对初学者非常不友好。为此,本文将给出详细的连接MySQL数据库的过程,并且是纯手工,不依赖于pom.xml和Web容器ÿ…...
thingsboard通过mqtt设备连接及数据交互---记录一次问题--1883端口没开,到服务器控制面板中打开安全组1883端口
1,链接不上:原因是1883端口没开,到服务器控制面板中打开安全组1883端口 2,参考链接: https://blog.csdn.net/bujingyun8/article/details/120024788...
联邦学习中的LoRA:FedLoRA
联邦学习中的LoRA:FedLoRA 联邦学习中的LoRA(Low-Rank Adaptation of Large Language Models)是一种用于在联邦学习场景下对大型语言模型进行低秩适应和高效微调的方法。以下是其原理及示例说明: 原理 低秩矩阵分解:在联邦学习中,通常会涉及到对预训练的大型模型进行微…...
PyTorch reshape函数介绍
torch.reshape 是 PyTorch 用于改变张量形状的函数之一。它不会改变张量的数据,而是重新组织其元素以适应新的形状。 reshape 的使用 torch.reshape(input, shape) → Tensorinput:输入张量。shape:新形状,使用整数或 -1 指定各维…...
Linux内核 -- 邮箱子系统之`mbox_controller` 的 `txdone_irq` 用法
Linux Kernel 中 mbox_controller 的 txdone_irq 用法 1. txdone_irq 的作用 txdone_irq 是一个布尔类型字段,用来指示邮件框控制器是否支持通过中断通知传输完成事件。 如果设置为 true: 硬件会在数据传输完成后生成中断。内核中相应的中断处理程序会…...
Linux/Ubuntu/银河麒麟 arm64 飞腾FT2000 下使用 arm64版本 linuxdeployqt 打包Qt程序
文章目录 一、前言二、环境三、准备1、下载Linuxdeployqt源码2、下载Appimagetool-aarch64.AppImage四、编译linuxdeployqt1.配置环境变量2.编译linuxdeployqt五、安装patchelf六、配置Appimagetool七、打包Qt程序重要提示:测试启动应用八、其他九、最后一、前言 因为项目需要…...
Excel | 空格分隔的行怎么导入excel?
准备工作:windows,一个记事本程序和微软的Excel软件。 打开记事本,选中所有内容,按CtrlA全选,然后复制(CtrlC)。 在Excel中,定位到你想粘贴的单元格,按CtrlV进行粘贴。粘贴后,你会在…...
如何将某两个提交去掉父提交的合并
q: 在一个两个月前的分支,我想保持纯净,但是需要把另一个变化很大的分支只将某两个提交的变更同步过来,基于idea的git操作该怎么做 a: 其实很多人会一下想到cherry pick,这个确实方便,但是会将父提交连带合…...
Windows下安装最新版的OpenSSL,并解决OpenSSL不是当前版本的问题,或者安装不正确的问题
文章目录 1. 文章引言1.1 需求描述1.2 简单介绍1.3 支持平台1.4 源码地址1.5 组件介绍2. 下载OpenSSL3. 安装OpenSSL5. 查看安装目录6. 解决OpenSSL的错误1. 文章引言 1.1 需求描述 今天接到一需求,解密php加密后的数据,由于php使用 openssl_encrypt的方式加密,java也需要使…...
Django 社团管理系统的设计与实现
标题:Django 社团管理系统的设计与实现 内容:1.摘要 本文介绍了 Django 社团管理系统的设计与实现。通过分析社团管理的需求,设计了系统的架构和功能模块,并使用 Django 框架进行了实现。系统包括社团信息管理、成员管理、活动管理、财务管理等功能&…...
android compose 串口通信
1.添加依赖 implementation("io.github.xmaihh:serialport:2.1.1") 2.添加SerialHelper派生类 class SerialPortHelper(portName:String,baudRate:Int): SerialHelper(portName,baudRate) {var receivedDataBuffer mutableListOf<Byte>()override fun onDa…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...
高效的后台管理系统——可进行二次开发
随着互联网技术的迅猛发展,企业的数字化管理变得愈加重要。后台管理系统作为数据存储与业务管理的核心,成为了现代企业不可或缺的一部分。今天我们要介绍的是一款名为 若依后台管理框架 的系统,它不仅支持跨平台应用,还能提供丰富…...
2.2.2 ASPICE的需求分析
ASPICE的需求分析是汽车软件开发过程中至关重要的一环,它涉及到对需求进行详细分析、验证和确认,以确保软件产品能够满足客户和用户的需求。在ASPICE中,需求分析的关键步骤包括: 需求细化:将从需求收集阶段获得的高层需…...
在Zenodo下载文件 用到googlecolab googledrive
方法:Figshare/Zenodo上的数据/文件下载不下来?尝试利用Google Colab :https://zhuanlan.zhihu.com/p/1898503078782674027 参考: 通过Colab&谷歌云下载Figshare数据,超级实用!!࿰…...
CentOS 7.9安装Nginx1.24.0时报 checking for LuaJIT 2.x ... not found
Nginx1.24编译时,报LuaJIT2.x错误, configuring additional modules adding module in /www/server/nginx/src/ngx_devel_kit ngx_devel_kit was configured adding module in /www/server/nginx/src/lua_nginx_module checking for LuaJIT 2.x ... not…...
qt 双缓冲案例对比
双缓冲 1.双缓冲原理 单缓冲:在paintEvent中直接绘制到屏幕,绘制过程被用户看到 双缓冲:先在redrawBuffer绘制到缓冲区,然后一次性显示完整结果 代码结构 单缓冲:所有绘制逻辑在paintEvent中 双缓冲:绘制…...
