【行为型模式】责任链模式
文章目录
- 1、简介
- 2、结构
- 3、实现方式
- 3.1、案例引入
- 3.2、结构分析
- 3.3、具体实现
- 4、责任链优缺点
- 5、应用场景
1、简介
责任链模式(Chain of Responsibility)是一种行为型设计模式,它允许对象在链上依次处理请求,用户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递,从而避免了请求发送者和接收者之间的直接耦合。具体来说,当一个请求进入责任链时,每个对象都有机会对该请求进行处理,如果当前对象无法处理该请求,则将其传递给下一个对象,直到找到能够处理请求的对象为止。
责任链模式在实际开发中非常常用,它可以帮助我们简化代码结构,提高可维护性和可扩展性。使用责任链模式可以避免代码中出现大量的条件语句,同时也使得代码更加灵活,易于修改和扩展。例如,在Web开发中,我们经常需要对请求进行权限校验、数据验证等操作,这些操作可以通过责任链模式来实现,从而使得代码更加清晰、易于维护。
2、结构
责任链模式由多个对象组成,每个对象都可以选择性地处理请求,并将请求传递给链中的下一个处理器。其结构包括以下几个要素:
- 抽象处理者(Handler):定义了一个处理请求的接口,并维护一个指向下一个处理器的引用;
- 具体处理者(Concrete Handler):实现了处理请求接口,如果能够处理请求则直接处理,否则将请求转发给下一个处理器;
- 客户端(Client):创建和组装责任链,并向其提交请求。
在这种结构中,客户端将请求发送给责任链的第一个处理器,如果该处理器无法处理请求,则会将请求转发给链中的下一个处理器,直到找到能够处理请求的处理器或者遍历完整个责任链为止。
3、实现方式
3.1、案例引入
假设某公司的员工老王因为需要为爱冲锋请假五天,他向项目组组长提交了请假申请,请假一天以下的假只需要小组长同意即可;请假1天到3天的假还需要部门经理同意;请求3天到7天还需要总经理同意才行,最终完成请假批准。
以上场景我们可以通过责任链模式来处理申请可以提高流程效率和响应速度,当某一个处理者权限不足时传递给更高级别的处理者,知道可以批准请假请求。
3.2、结构分析
在上述场景中,责任链模式中的各个角色分别对应如下:
-
Handler(抽象处理者):该类是所有具体处理者的抽象基类,定义了处理请求的接口和维护后继处理者的链表。在上述代码中,Handler类中定义了numStart、numEnd和nextHandler字段以及submit()和handleLeave()方法;
-
GroupLeader、Manager和GeneralManager(具体处理者):这些类是实际处理请求的角色,根据自己所能处理的请假天数范围来决定是否处理该请求,如果不能处理则将请求传递给下一个处理者。在上述代码中,这三个类分别继承了Handler类,并且覆盖了handleLeave()方法;
-
LeaveRequest(请求对象):表示需要被处理的请求,在责任链模式中被依次传递给各个处理者进行处理。在上述代码中,LeaveRequest类包含了姓名、请假天数和请假内容三个属性。
3.3、具体实现
首先,定义了一个LeaveRequest类,表示请假条,其中包含姓名、请假天数和请假内容三个属性。
//请假条(请求对象)
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;}
}
定义了一个Handler抽象类,表示领导处理者,包含处理请假条的方法handleLeave()和提交请假条的方法submit()。其中,submit()方法接收一个请假条对象,如果该领导能够处理该请假条,则会调用handleLeave()方法进行处理,并且如果还有上级领导则会继续提交给上级领导处理,直到没有上级领导为止。
//处理者抽象类
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;}//提交请假条public final void submit(LeaveRequest leave){if(0 == this.numStart){return;}//如果请假天数达到该领导者的处理要求if(leave.getNum() >= this.numStart){this.handleLeave(leave);//如果还有上级 并且请假天数超过了当前领导的处理范围if(null != this.nextHandler && leave.getNum() > numEnd){this.nextHandler.submit(leave);//继续提交} else {System.out.println("流程结束");}}}//各级领导处理请假条方法protected abstract void handleLeave(LeaveRequest leave);
}
定义了三个具体的领导处理者类GroupLeader、Manager和GeneralManager,分别代表小组长、部门经理和总经理。这三个类都继承了Handler类,并且在构造方法中传入了自己能够处理的请假天数区间。
//小组长
public class GroupLeader extends Handler {public GroupLeader() {//小组长处理1-3天的请假super(Handler.NUM_ONE, Handler.NUM_THREE);}@Overrideprotected void handleLeave(LeaveRequest leave) {System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");System.out.println("小组长审批:同意。");}
}//部门经理
public class Manager extends Handler {public Manager() {//部门经理处理3-7天的请假super(Handler.NUM_THREE, Handler.NUM_SEVEN);}@Overrideprotected void handleLeave(LeaveRequest leave) {System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");System.out.println("部门经理审批:同意。");}
}//总经理
public class GeneralManager extends Handler {public GeneralManager() {//部门经理处理7天以上的请假super(Handler.NUM_SEVEN);}@Overrideprotected void handleLeave(LeaveRequest leave) {System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");System.out.println("总经理审批:同意。");}
}
在客户端类Client中,创建了一个请假条对象leave,以及三个具体的领导处理者对象groupLeader、manager和generalManager,并且将它们按照审批顺序连接起来,即小组长的上级领导是部门经理,部门经理的上级领导是总经理。最后,调用groupLeader的submit()方法提交请假条。
//测试类
public class Client {public static void main(String[] args) {//请假条来一张LeaveRequest leave = new LeaveRequest("老王",5,"为爱冲锋");//各位领导GroupLeader groupLeader = new GroupLeader();Manager manager = new Manager();GeneralManager generalManager = new GeneralManager();//小组长的领导是部门经理groupLeader.setNextHandler(manager);//部门经理的领导是总经理manager.setNextHandler(generalManager);//之所以在这里设置上级领导,是因为可以根据实际需求来更改设置,如果实战中上级领导人都是固定的,则可以移到领导实现类中。//提交申请groupLeader.submit(leave);}
}
运行结果如下
老王请假5天,为爱冲锋。
小组长审批:同意。
部门经理审批:同意。
流程结束
4、责任链优缺点
责任链模式的优点包括:
-
解耦责任:将请求和处理分离开来,每个处理器只需关注自己负责处理的请求类型,不需要知道整个请求处理流程,从而实现解耦。
-
灵活性增强:可以动态地新增或者修改请求处理器,而不需要修改已经存在的代码,提高了系统的灵活性。
-
可扩展性增强:可以方便地增加新的处理器,而且不需要修改已有的处理器,方便了系统的扩展。
-
单一职责原则:每个请求处理器只负责自己所能处理的请求类型,符合单一职责原则。
责任链模式的缺点包括:
-
性能问题:由于处理请求的流程是递归进行的,或者是通过循环链表实现的,所以在一些情况下可能会导致性能问题。
-
责任链过长:如果责任链比较长,请求可能需要遍历整个链才能被处理,这会降低请求的处理效率。
-
请求未被处理:如果责任链没有对某个请求类型进行处理器的注册,那么该请求就无法被处理。
优点 | 缺点 |
---|---|
解耦责任,将请求和处理分离 | 性能问题 |
灵活性增强,动态新增或修改请求处理器 | 责任链过长 |
可扩展性增强,方便增加新的处理器 | 请求未被处理 |
符合单一职责原则 |
5、应用场景
责任链模式通常适用于以下应用场景:
-
处理请求:当需要处理一些事件或者请求时,可以使用责任链模式来实现多个处理器依次进行处理的流程。
-
安全控制:在安全控制系统中,可以通过责任链模式来实现权限的验证和授权,每个处理器负责验证某种权限,只有当所有的处理器都通过验证后,才能完成授权操作,否则授权失败。
-
日志记录:在日志记录系统中,可以使用责任链模式来按照顺序记录不同级别的日志信息,比如 INFO、WARNING 和 ERROR 等级别的日志信息。
-
异常处理:在异常处理系统中,多个异常处理器可以组成一个责任链,当出现异常时,责任链会按照顺序依次处理异常,并尝试将其解决掉。
-
消息过滤:在消息过滤系统中,可以使用责任链模式来实现消息的过滤和处理,每个处理器根据自己的条件对消息进行过滤和处理,最终得到处理结果。
Java和Spring中有许多地方都用到了责任链模式,其中比较典型的包括:
-
Java Servlet中的Filter:Servlet Filter是Java Web应用程序中使用的一种技术,它可以在Servlet执行之前或之后截取请求和响应。Filter通常被组织成一个责任链来处理请求;
-
Spring Security中的AccessDecisionManager:Spring Security是一个强大的安全框架,其中的AccessDecisionManager接口就是一个很好的责任链模式实现。AccessDecisionManager负责决定当前用户是否有权限访问某个资源,它由多个Voter组成,每个Voter对应一种投票策略;
-
Spring AOP中的Advice Chain:Spring AOP是Spring框架中非常重要的一个模块,Advice Chain就是一个很好的责任链模式实现。Advice Chain由多个Advice对象组成,每个Advice对应一种横切关注点;
-
Java NIO中的Channel Handler:Java NIO(New IO)是Java SE 1.4引入的一种新的I/O机制,它提供了更快、更灵活的I/O操作方式。在Java NIO中,Channel Handler就是一个很好的责任链模式实现,它将数据的读写过程交给一系列的处理器来完成;
-
Java异常处理机制中的Exception Handler:Java中的异常处理机制也是一个很好的责任链模式实现,当某个方法抛出异常时,Java会尝试将异常交给方法的调用方,在调用方处理不了异常时,Java会继续将异常向上抛出,直到被处理为止。
相关文章:

【行为型模式】责任链模式
文章目录1、简介2、结构3、实现方式3.1、案例引入3.2、结构分析3.3、具体实现4、责任链优缺点5、应用场景1、简介 责任链模式(Chain of Responsibility)是一种行为型设计模式,它允许对象在链上依次处理请求,用户只需要将请求发送到责任链上即可…...
C++命令模式 指挥家:掌控命令模式之美
C指挥家:掌控命令模式之美 (C Conductor: Master the Beauty of Command Pattern一、引言 (Introduction)1.1 命令模式概述 (Overview of Command Pattern)1.2 命令模式的应用场景 (Application Scenarios of Command Pattern)二、命令模式的基本概念 (Basic Concep…...

学会 制作极简搜索浏览器 —— 并将 ChatGPT 接入浏览器
前期回顾 Vue3 Ts Vite pnpm 项目中集成 —— eslint 、prettier、stylelint、husky、commitizen_0.活在风浪里的博客-CSDN博客搭建VIte Ts Vue3项目并集成eslint 、prettier、stylelint、huskyhttps://blog.csdn.net/m0_57904695/article/details/129950163?spm1001.2…...

NumPy 秘籍中文第二版:六、特殊数组和通用函数
原文:NumPy Cookbook - Second Edition 协议:CC BY-NC-SA 4.0 译者:飞龙 在本章中,我们将介绍以下秘籍: 创建通用函数查找勾股三元组用chararray执行字符串操作创建一个遮罩数组忽略负值和极值使用recarray函数创建一…...
各种交叉编译工具链的区别
目录 1 命名规则 2 实例 2.1 arm-none-eabi-gcc 2.2 arm-none-linux-gnueabi-gcc 2.3 arm-eabi-gcc 2.4 armcc 2.5 arm-none-uclinuxeabi-gcc 和 arm-none-symbianelf-gcc 3 gnueabi和gnueabihf的区别(硬浮点、软浮点) 4 Linaro公司出品的交叉编译工具链 5 ARM公司出…...

密度聚类算法(DBSCAN)实验案例
密度聚类算法(DBSCAN)实验案例 描述 DBSCAN是一种强大的基于密度的聚类算法,从直观效果上看,DBSCAN算法可以找到样本点的全部密集区域,并把这些密集区域当做一个一个的聚类簇。DBSCAN的一个巨大优势是可以对任意形状…...

第07章_面向对象编程(进阶)
第07章_面向对象编程(进阶) 讲师:尚硅谷-宋红康(江湖人称:康师傅) 官网:http://www.atguigu.com 本章专题与脉络 1. 关键字:this 1.1 this是什么? 在Java中,this关键字不算难理解…...
异常的讲解(2)
目录 throws异常处理 基本介绍 throws异常处理注意事项和使用细节 自定义异常 基本概念 自定义异常的步骤 throw 和throws的区别 本章作业 第一题 第二题 第三题 第四题 throws异常处理 基本介绍 1)如果一个方法(中的语句执行时)可能生成某种异常,但是…...

jvm内存结构
1. 栈 程序计数器 2. 虚拟机栈 3. 本地方法栈 4. 堆 5. 方法区 1.2栈内存溢出 栈帧过多导致栈内存溢出 /*** 演示栈内存溢出 java.lang.StackOverflowError* -Xss256k*/ public class Demo1_2 {private static int count;public static void main(String[] args) {try {meth…...

要刹车?生成式AI迎新规、行业连发ChatGPT“警报”、多国考虑严监管
4月13日消息,据中国移动通信联合会元宇宙产业工作委员会网站,中国移动通信联合会元宇宙产业工作委员会、中国通信工业协会区块链专业委员会等,共同发布“关于元宇宙生成式人工智能(类 ChatGPT)应用的行业提示”。提示内…...
轻松掌握Qt FTP 机制:实现高效文件传输
轻松掌握Qt FTP:实现高效文件传输一、简介(Introduction)1.1 文件传输协议(FTP)Qt及其网络模块(Qt and its Network Module)QNetwork:二、QNetworkAccessManager上传实例(Qt FTP Upl…...

用AI帮我写一篇关于FPGA的文章,并推荐最热门的FPGA开源项目
FPGA定义 FPGA(Field Programmable Gate Array)是一种可编程逻辑器件,可以在硬件电路中实现各种不同的逻辑功能。与ASIC(Application Specific Integrated Circuit,特定应用集成电路)相比,FPGA…...
从兴趣或问题出发
当我们还沉寂在移动互联网给生活带来众多便利中,以 ChartGPT 为代表的 AI 时代已彻底到来。科技的发展,时刻在改变着我们的生活,我们需要不断地学习新知识和掌握新技能才能享受变化带来的便利,以及自身不被社会淘汰。 因此&#…...

C++ | 探究拷贝对象时的一些编译器优化
👑作者主页:烽起黎明 🏠学习社区:烈火神盾 🔗专栏链接:C 文章目录前言一、传值传参二、传引用传参三、传值返回拷贝构造和赋值重载的辨析四、传引用返回【❌】五、传匿名对象返回六、总计与提炼前言 在传参…...

linux工具gcc/g++/gdb/git的使用
目录 gcc/g 基本概念 指令集 函数库 (重要) gdb使用 基本概念 指令集 项目自动化构建工具make/makefile 进度条小程序 编辑 git三板斧 创建仓库 git add git commit git push git status git log gcc/g 基本概念 gcc/g称为编译器…...

Direct3D 12——纹理——纹理
纹理不同于缓冲区资源,因为缓冲区资源仅存储数据数组,而纹理却可以具有多个mipmap层级(后 文有介绍),GPU会基于这个层级进行相应的特殊操作,例如运用过滤器以及多重采样。支持这些特殊 的操作纹理资源都被限定为一些特定的数据格式…...

产品经理必读 | 俞军产品经理十二条军规
最近在学习《俞军产品方法论》,觉得俞军总结的十二条产品经理原则非常受用,分享给大家。 01. 产品经理首先是产品的深度用户 自己设计的产品都没使用过的产品经理,如何明白用户使用的问题,如何解决问题,所以产品经理肯…...

【机器视觉1】光源介绍与选择
文章目录一、常见照明光源类型二、照明光源对比三、照明技术3.1 亮视野与暗视野3.2 低角度照明3.3 前向光直射照明3.4 前向光漫射照明3.5 背光照明-测量系统的最佳选择3.6 颜色与补色示例3.7 偏光技术应用四、镜头4.1 镜头的几个概念4.2 影响图像质量的关键因素4.3 成像尺寸4.4…...

【三十天精通Vue 3】第十一天 Vue 3 过渡和动画详解
✅创作者:陈书予 🎉个人主页:陈书予的个人主页 🍁陈书予的个人社区,欢迎你的加入: 陈书予的社区 🌟专栏地址: 三十天精通 Vue 3 文章目录引言一、Vue 3 过度和动画概述1.1过度和动画的简介二、Vue 3 过度2…...

基于多种流量检测引擎识别pcap数据包中的威胁
在很多的场景下,会需要根据数据包判断数据包中存在的威胁。针对已有的数据包,如何判断数据包是何种攻击呢? 方法一可以根据经验,对于常见的WEB类型的攻击,比如SQL注入,命令执行等攻击,是比较容…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...

有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...

springboot 日志类切面,接口成功记录日志,失败不记录
springboot 日志类切面,接口成功记录日志,失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...