当前位置: 首页 > news >正文

【行为型模式】责任链模式

文章目录

    • 1、简介
    • 2、结构
    • 3、实现方式
      • 3.1、案例引入
      • 3.2、结构分析
      • 3.3、具体实现
    • 4、责任链优缺点
    • 5、应用场景

1、简介

责任链模式(Chain of Responsibility)是一种行为型设计模式,它允许对象在链上依次处理请求,用户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递,从而避免了请求发送者和接收者之间的直接耦合。具体来说,当一个请求进入责任链时,每个对象都有机会对该请求进行处理,如果当前对象无法处理该请求,则将其传递给下一个对象,直到找到能够处理请求的对象为止。

处理者依次排列,组成一条链

责任链模式在实际开发中非常常用,它可以帮助我们简化代码结构,提高可维护性和可扩展性。使用责任链模式可以避免代码中出现大量的条件语句,同时也使得代码更加灵活,易于修改和扩展。例如,在Web开发中,我们经常需要对请求进行权限校验、数据验证等操作,这些操作可以通过责任链模式来实现,从而使得代码更加清晰、易于维护。

2、结构

责任链模式由多个对象组成,每个对象都可以选择性地处理请求,并将请求传递给链中的下一个处理器。其结构包括以下几个要素:

  1. 抽象处理者(Handler):定义了一个处理请求的接口,并维护一个指向下一个处理器的引用;
  2. 具体处理者(Concrete Handler):实现了处理请求接口,如果能够处理请求则直接处理,否则将请求转发给下一个处理器;
  3. 客户端(Client):创建和组装责任链,并向其提交请求。

img

在这种结构中,客户端将请求发送给责任链的第一个处理器,如果该处理器无法处理请求,则会将请求转发给链中的下一个处理器,直到找到能够处理请求的处理器或者遍历完整个责任链为止。

3、实现方式

3.1、案例引入

假设某公司的员工老王因为需要为爱冲锋请假五天,他向项目组组长提交了请假申请,请假一天以下的假只需要小组长同意即可;请假1天到3天的假还需要部门经理同意;请求3天到7天还需要总经理同意才行,最终完成请假批准。

以上场景我们可以通过责任链模式来处理申请可以提高流程效率和响应速度,当某一个处理者权限不足时传递给更高级别的处理者,知道可以批准请假请求。

image-20230414212453862

3.2、结构分析

在上述场景中,责任链模式中的各个角色分别对应如下:

  1. Handler(抽象处理者):该类是所有具体处理者的抽象基类,定义了处理请求的接口和维护后继处理者的链表。在上述代码中,Handler类中定义了numStart、numEnd和nextHandler字段以及submit()和handleLeave()方法;

  2. GroupLeader、Manager和GeneralManager(具体处理者):这些类是实际处理请求的角色,根据自己所能处理的请假天数范围来决定是否处理该请求,如果不能处理则将请求传递给下一个处理者。在上述代码中,这三个类分别继承了Handler类,并且覆盖了handleLeave()方法;

  3. LeaveRequest(请求对象):表示需要被处理的请求,在责任链模式中被依次传递给各个处理者进行处理。在上述代码中,LeaveRequest类包含了姓名、请假天数和请假内容三个属性。

img

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、责任链优缺点

责任链模式的优点包括:

  1. 解耦责任:将请求和处理分离开来,每个处理器只需关注自己负责处理的请求类型,不需要知道整个请求处理流程,从而实现解耦。

  2. 灵活性增强:可以动态地新增或者修改请求处理器,而不需要修改已经存在的代码,提高了系统的灵活性。

  3. 可扩展性增强:可以方便地增加新的处理器,而且不需要修改已有的处理器,方便了系统的扩展。

  4. 单一职责原则:每个请求处理器只负责自己所能处理的请求类型,符合单一职责原则。

责任链模式的缺点包括:

  1. 性能问题:由于处理请求的流程是递归进行的,或者是通过循环链表实现的,所以在一些情况下可能会导致性能问题。

  2. 责任链过长:如果责任链比较长,请求可能需要遍历整个链才能被处理,这会降低请求的处理效率。

  3. 请求未被处理:如果责任链没有对某个请求类型进行处理器的注册,那么该请求就无法被处理。

优点缺点
解耦责任,将请求和处理分离性能问题
灵活性增强,动态新增或修改请求处理器责任链过长
可扩展性增强,方便增加新的处理器请求未被处理
符合单一职责原则

5、应用场景

责任链模式通常适用于以下应用场景:

  1. 处理请求:当需要处理一些事件或者请求时,可以使用责任链模式来实现多个处理器依次进行处理的流程。

  2. 安全控制:在安全控制系统中,可以通过责任链模式来实现权限的验证和授权,每个处理器负责验证某种权限,只有当所有的处理器都通过验证后,才能完成授权操作,否则授权失败。

  3. 日志记录:在日志记录系统中,可以使用责任链模式来按照顺序记录不同级别的日志信息,比如 INFO、WARNING 和 ERROR 等级别的日志信息。

  4. 异常处理:在异常处理系统中,多个异常处理器可以组成一个责任链,当出现异常时,责任链会按照顺序依次处理异常,并尝试将其解决掉。

  5. 消息过滤:在消息过滤系统中,可以使用责任链模式来实现消息的过滤和处理,每个处理器根据自己的条件对消息进行过滤和处理,最终得到处理结果。

Java和Spring中有许多地方都用到了责任链模式,其中比较典型的包括:

  1. Java Servlet中的Filter:Servlet Filter是Java Web应用程序中使用的一种技术,它可以在Servlet执行之前或之后截取请求和响应。Filter通常被组织成一个责任链来处理请求;

  2. Spring Security中的AccessDecisionManager:Spring Security是一个强大的安全框架,其中的AccessDecisionManager接口就是一个很好的责任链模式实现。AccessDecisionManager负责决定当前用户是否有权限访问某个资源,它由多个Voter组成,每个Voter对应一种投票策略;

  3. Spring AOP中的Advice Chain:Spring AOP是Spring框架中非常重要的一个模块,Advice Chain就是一个很好的责任链模式实现。Advice Chain由多个Advice对象组成,每个Advice对应一种横切关注点;

  4. Java NIO中的Channel Handler:Java NIO(New IO)是Java SE 1.4引入的一种新的I/O机制,它提供了更快、更灵活的I/O操作方式。在Java NIO中,Channel Handler就是一个很好的责任链模式实现,它将数据的读写过程交给一系列的处理器来完成;

  5. Java异常处理机制中的Exception Handler:Java中的异常处理机制也是一个很好的责任链模式实现,当某个方法抛出异常时,Java会尝试将异常交给方法的调用方,在调用方处理不了异常时,Java会继续将异常向上抛出,直到被处理为止。

相关文章:

【行为型模式】责任链模式

文章目录1、简介2、结构3、实现方式3.1、案例引入3.2、结构分析3.3、具体实现4、责任链优缺点5、应用场景1、简介 责任链模式(Chain of Responsibility)是一种行为型设计模式,它允许对象在链上依次处理请求,用户只需要将请求发送到责任链上即可&#xf…...

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注入,命令执行等攻击,是比较容…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...