一文带你彻底搞懂什么是责任链模式!!

文章目录

    • 什么是责任链模式?
    • 详细示例
    • SpingMVC 中的责任链模式使用
    • 总结

在这里插入图片描述

什么是责任链模式?

在我们日常生活中,经常会出现一种场景:一个请求需要经过多个对象的处理才能得到最终的结果。比如,一个请假申请,需要经过组长、部门经理、总经理等多个级别的审批。这种场景下,使用责任链模式是一种非常优雅的解决方案。

责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它的主要目的是将请求的发送者和接收者解耦,使得多个对象都有机会处理这个请求。这种模式通过将请求沿着处理者链进行传递,直到有一个对象处理它为止。

在这里插入图片描述

在责任链模式中,主要涉及以下三个角色:

  1. 抽象处理者(Handler):处理器抽象接口,定义了处理请求的方法和执行下一步处理的处理器。
  2. 具体处理者(ConcreteHandler):实现抽象处理者接口,具体处理请求的逻辑在这里实现。如果不能处理当前请求,则将请求传递给下一个处理者。
  3. 客户端(Client):负责创建并组装责任链,将请求发送给链中的第一个处理者。

在这里插入图片描述

在这里插入图片描述

代码:

// 抽象处理器
public abstract class Handler {private Handler next;public Handler getNext() {return next;}public void setNext(Handler next) {this.next = next;}public abstract void handle(Object request);
}// 具体处理器 1
public class ConcreteHandler1 extends Handler {@Overridepublic void handle(Object request) {System.out.println("concrete handler 1 execute request. request: " + request);if (getNext() != null) {getNext().handle(request);}}
}// 具体处理器 2
public class ConcreteHandler2 extends Handler {@Overridepublic void handle(Object request) {System.out.println("concrete handler 2 execute request. request: " + request);if (getNext() != null){getNext().handle(request);}}
}// 具体处理器 3
public class ConcreteHandler3 extends Handler {@Overridepublic void handle(Object request) {System.out.println("concrete handler 3 execute request. request: " + request);if (getNext() != null) {getNext().handle(request);}}
}public static void main(String[] args) {Handler concreteHandler1 = new ConcreteHandler1();Handler concreteHandler2 = new ConcreteHandler2();Handler concreteHandler3 = new ConcreteHandler3();concreteHandler1.setNext(concreteHandler2);concreteHandler2.setNext(concreteHandler3);concreteHandler1.handle("my request.");
}

从上面的代码我们可以看到其实责任链模式是非常简单的,但是其中有几个点需要注意一下:

  • 首先我们需要对整个责任链进行初始化,即设置每个处理器的 next
  • 在每个具体处理器处理完之后需要手动调用下一个处理器的 handle 方法来执行下一步处理,这里其实还可以使用模板方法模式进行优化

控制台输出如下:

concrete handler 1 execute request. request: my request.
concrete handler 2 execute request. request: my request.
concrete handler 3 execute request. request: my request.

详细示例

日常请假为例。请假申请会先到你的直属 leader 处审批,审批通过后再到部门 leader 处审批,部门 leader 通过后,最后到人事处报备记录请假天数。

如果在传统企业里面,我们需要手写一份请假表,然后跑到直属 leader 办公室,让直属 leader 签字,然后再到部门 leader 办公室签字,最后还要跑到人事处上交请假单,这样相当于发出了三次请求,才能走完整个请假流程。

在这里插入图片描述

但是当我们使用责任链模式后整个请假流程就变的简单了,我们只需要发起一次请假请求,接下来你的请假请求便会自动的在审批人中间进行流转,这个时候我们的责任链模式便派上用场。

在这里插入图片描述

代码如下:

// 请假抽象处理器
public abstract class DayOffHandler {private DayOffHandler next;public DayOffHandler getNext() {return next;}public void setNext(DayOffHandler next) {this.next = next;}public abstract void handle(String request);}
// 直属 leader 处理
public class GroupLeaderHandler extends DayOffHandler {@Overridepublic void handle(String request) {System.out.println("直属 leader 审查: " + request);System.out.println("同意请求");if (getNext() != null) {getNext().handle(request);}}
}
// 部门 leader 处理
public class DepartmentLeaderHandler extends DayOffHandler{@Overridepublic void handle(String request) {System.out.println("部门 leader 审查: " + request);System.out.println("同意请求");if (getNext() != null) {getNext().handle(request);}}
}
// 人事处处理
public class HRHandler extends DayOffHandler {@Overridepublic void handle(String request) {System.out.println("人事处审查: " + request);System.out.println("同意请求,记录请假");if (getNext() != null) {getNext().handle(request);}}
}

客户端:

public static void main(String[] args) {DayOffHandler groupLeaderHandler = new GroupLeaderHandler();DayOffHandler departmentLeaderHandler = new DepartmentLeaderHandler();DayOffHandler hrHandler = new HRHandler();groupLeaderHandler.setNext(departmentLeaderHandler);departmentLeaderHandler.setNext(hrHandler);System.out.println("收到面试通知,需要请假");String request = "家中有事,请假半天,望批准";System.out.println("发起请求:");groupLeaderHandler.handle(request);
}

上面的代码定义了请假抽象处理类和三个具体的处理人,我们需要将这三个处理人的流程初始化串联起来,并且一步步的执行下去

结果:

收到面试通知,需要请假
发起请求:
直属 leader 审查: 家中有事,请假半天,望批准
同意请求
部门 leader 审查: 家中有事,请假半天,望批准
同意请求
人事处审查: 家中有事,请假半天,望批准
同意请求,记录请假

SpingMVC 中的责任链模式使用

在 SpringMVC 中的 Interceptor 用到了责任链模式。首先来看看 Interceptor 的抽象处理类;

public interface HandlerInterceptor {default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return true;}default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {}default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {}
}

在抽象处理类中,定义了三个方法,分别是处理前置处理器、后置处理器和整个流程完成之后的处理。通过 HandlerExecutionChain 将拦截器串联起来,在 HandlerExecutionChain 中,我们需要关注 applyPreHandleapplyPostHandletriggerAfterCompletion 三个方法,这三个方法分别执行了拦截器中所定义的 preHandlepostHandleafterCompletion 方法。并且从代码中也能够看处,和前面的过滤器一样,所有的拦截器都存放在 interceptors 数组中,并在三个方法中遍历 interceptors 数组依次执行相应的方法

public class HandlerExecutionChain {@Nullableprivate HandlerInterceptor[] interceptors;boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {HandlerInterceptor[] interceptors = this.getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {HandlerInterceptor interceptor = interceptors[i];if (!interceptor.preHandle(request, response, this.handler)) {this.triggerAfterCompletion(request, response, (Exception)null);return false;}}}return true;}void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {HandlerInterceptor[] interceptors = this.getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {for(int i = interceptors.length - 1; i >= 0; --i) {HandlerInterceptor interceptor = interceptors[i];interceptor.postHandle(request, response, this.handler, mv);}}}void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception {HandlerInterceptor[] interceptors = this.getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {for(int i = this.interceptorIndex; i >= 0; --i) {HandlerInterceptor interceptor = interceptors[i];try {interceptor.afterCompletion(request, response, this.handler, ex);} catch (Throwable var8) {logger.error("HandlerInterceptor.afterCompletion threw exception", var8);}}}}
}

总结

责任链模式是常见的设计模式,各个不同职责的处理器串联起来,通过一次请求便能够执行完每个处理器的处理方法。

通过这样的方式请求的发送者只需发出一次请求同时也不需要知道详细的链路结构;而请求的接送方只关心自己的处理逻辑,自己处理完成之后将请求传递给下一个接收者,从而完成自己的任务,这样便实现了请求发送者和接收者的解耦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3223895.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

保姆级教程:Linux (Ubuntu) 部署流光卡片开源 API

流光卡片 API 开源地址 Github&#xff1a;https://github.com/ygh3279799773/streamer-card 流光卡片 API 开源地址 Gitee&#xff1a;https://gitee.com/y-gh/streamer-card 流光卡片在线使用地址&#xff1a;https://fireflycard.shushiai.com/ 等等&#xff0c;你说你不…

如何在Excel中对一个或多个条件求和?

在Excel中&#xff0c;基于一个或多个条件的求和值是我们大多数人的常见任务&#xff0c;SUMIF函数可以帮助我们根据一个条件快速求和&#xff0c;而SUMIFS函数可以帮助我们对多个条件求和。 本文&#xff0c;我将描述如何在Excel中对一个或多个条件求和&#xff1f; 在Excel中…

2020 ICPC Shanghai Site B. Mine Sweeper II 题解 构造 鸽巢原理

Mine Sweeper II 题目描述 A mine-sweeper map X X X can be expressed as an n m n\times m nm grid. Each cell of the grid is either a mine cell or a non-mine cell. A mine cell has no number on it. Each non-mine cell has a number representing the number of…

gif压缩大小但不改变画质的最佳方法,7个gif压缩免费工具别错过!

你会不会也碰到过当你需要在自媒体平台上上传gif文件时&#xff0c;你会发现网页端最大限制为15MB&#xff0c;而手机端最大限制为5MB。那么如何在不不改变画质的同时压缩gif大小呢&#xff1f;如今&#xff0c;由于其特殊的动画以及快速传输的特点&#xff0c;gif文件已经成为…

原创作品—数据可视化大屏

设计数据可视化大屏时&#xff0c;用户体验方面需注重以下几点&#xff1a;首先&#xff0c;确保大屏信息层次分明&#xff0c;主要数据突出显示&#xff0c;次要信息适当弱化&#xff0c;帮助用户快速捕捉关键信息。其次&#xff0c;设计应直观易懂&#xff0c;避免复杂难懂的…

Zabbix自动发现

目录 自动发现的主要特点包括&#xff1a; 如何配置自动发现&#xff1a; 实验步骤 1. 创建自动发现规则 2. 给自动发现规则创建动作 3. 给新主机安装agent 在 Zabbix 中&#xff0c;自动发现&#xff08;Auto Discovery&#xff09;是一种强大的功能&#xff0c;用于自…

jmeter持续学习之----性能初级一些概念和指标

服务端为什么要进行性能测试 大量用户下&#xff0c;系统能否稳定运行&#xff08;比较多&#xff09; 用于硬件服务器的选型 用于软件技术的选型 性能测试关注的点 用户角度:响应时间 资源占用:并发用户数,TPS,资源占用(cpu,内存,JVM) 性能测试策略 基准测试:单用户测试,对…

WEB安全基础:网络安全常用术语

一、攻击类别 漏洞&#xff1a;硬件、软件、协议&#xff0c;代码层次的缺陷。 后⻔&#xff1a;方便后续进行系统留下的隐蔽后⻔程序。 病毒&#xff1a;一种可以自我复制并传播&#xff0c;感染计算机和网络系统的恶意软件(Malware)&#xff0c;它能损害数据、系统功能或拦…

实时温湿度监测系统:Micropython编码ESP32与DHT22模块的无线数据传输与PC端接收项目

实时温湿度监测系统 前言项目目的项目材料项目步骤模拟ESP32接线连接测试搭建PC端ESP32拷录环境对ESP32进行拷录PC端搭建桌面组件本地数据接收桌面小组件部分 实验总结 前言 人生苦短&#xff0c;我用Python。 由于我在日常工作中经常使用Python&#xff0c;因此在进行该项目…

Excel第28享:如何新建一个Excel表格

一、背景需求 小姑电话说&#xff1a;要新建一个表格&#xff0c;并实现将几个单元格进行合并的需求。 二、解决方案 1、在电脑桌面上空白地方&#xff0c;点击鼠标右键&#xff0c;在下拉的功能框中选择“XLS工作表”或“XLSX工作表”都可以&#xff0c;如下图所示。 之后&…

C++基础知识:数组,数组是什么,数组的特点是什么?一维数组的三种定义方式,以及代码案例

1.数组的定义&#xff1a; 数组&#xff0c;就是一个集合&#xff0c;里面存放了相同类型的数据元素 2.数组的特点&#xff1a; 特点1:数组中的每个数据元素都是相同的数据类型 特点2:数组是由连续的内存位置组成的 3. 一维数组定义方式 维数组定义的三种方式: 1.数据类型 …

Studio One直播声音怎么调 Studio One直播没有声音输出怎么办 studio one如何设置声音变好听

Studio One做为新生代音乐工作站&#xff0c;凭借更低的价格和完备的功能&#xff0c;获得了音乐人和直播行业工作者的青睐&#xff0c;尤其是对硬件声卡的适配支持更好&#xff0c;特别适合用来配合线上教学和电商带货。 一、Studio One直播声音怎么调 在Studio One进行直播时…

linux使用chattr与lsattr设置文件/目录防串改

背景 linux服务器下,防止某个文件/目录被串改(增删改),可以使用chattr与lsattr设置,这是一种保护机制,用于防止意外地修改或删除重要的文件内容。 chattr与lsattr使用 1.设置目录 图中/tmp/zhk,设置目录属性文件可能被设置为不可更改(immutable)或者只追加(append …

0302GPIO外设输入功能

GPIO外设输入功能 输入部分硬件电路按键简介传感器模块简介按键和传感器模块的硬件电路 C语言的学习C语言数据类型宏定义typedef结构体枚举C语言知识总结 按键控制LED灯&光敏传感器蜂鸣器GPIO总结GPIO使用方法总结模块化编程的方法&#xff1a; 两个程序&#xff1a;按键控…

前端图表库G2快速上手

文档地址&#xff1a; https://g2-v3.antv.vision/zh/docs/manual/getting-started/ https://g2.antv.antgroup.com/ 安装&#xff1a; pnpm i antv/g2在vue3中使用&#xff1a; <script setup> import {Chart} from antv/g2; import {onMounted} from "vue"…

系统架构师考点--信息系统基础知识

大家好。今天我们来总结一下信息系统基础知识的相关考点&#xff0c;每年都会考&#xff0c;一般是在上午场选择题中&#xff0c;占3分左右&#xff0c;其次下午场论文也有可能会出相关的考题。 一、信息系统概述 信息系统&#xff1a; 是由计算机硬件、网络和通信设备、计算…

鸿蒙语言基础类库:【@ohos.util.Deque (线性容器Deque)】

线性容器Deque 说明&#xff1a; 本模块首批接口从API version 8开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 Deque&#xff08;double ended queue&#xff09;根据循环队列的数据结构实现&#xff0c;符合先进先出以及先进后出的特点&…

ESP32的I2S引脚及支持的音频标准使用说明

ESP32 I2S 接口 ESP32 有 2 个标准 I2S 接口。这 2 个接口可以以主机或从机模式&#xff0c;在全双工或半双工模式下工作&#xff0c;并且可被配置为 8/16/32/48/64-bit 的输入输出通道&#xff0c;支持频率从 10 kHz 到 40 MHz 的 BCK 时钟。当 1 个或 2 个 被配置为主机模式…

nvm安装报错(镜像问题)

一、问题报错 安装的时候如果跟着网上早些时候的配置&#xff0c;调整了setting文件&#xff0c;配置镜像的话&#xff0c;可能报这个错误。 这个是因为他没检索到后面的链接地址&#xff0c;因为镜像的地址新的已经更换了。使用这个吧&#xff1a; node_mirror: https://npm…

华为、H3C、锐捷、思科四大设备厂商交换机配置命令总结合辑

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 下午好&#xff0c;我的网工朋友。 一直以来&#xff0c;对于华为、H3C、锐捷、思科交换机的命令配置&#xff0c;不断的有朋友留言&#xff0c;四…