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

文章目录

    • 什么是责任链模式?
    • 详细示例
    • 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 {
    @Override
    public 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 {
    @Override
    public 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 {
    @Override
    public 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 {
    @Override
    public void handle(String request) {
        System.out.println("直属 leader 审查: " + request);
        System.out.println("同意请求");
        if (getNext() != null) {
            getNext().handle(request);
        }
    }
}
// 部门 leader 处理
public class DepartmentLeaderHandler extends DayOffHandler{
    @Override
    public void handle(String request) {
        System.out.println("部门 leader 审查: " + request);
        System.out.println("同意请求");
        if (getNext() != null) {
            getNext().handle(request);
        }
    }
}
// 人事处处理
public class HRHandler extends DayOffHandler {
    @Override
    public 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 {
    @Nullable
    private 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);
                }
            }
        }

    }
}

总结

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

集训 Day 2 模拟赛总结

复盘 7&#xff1a;30 开题 想到几天前被普及组难度模拟赛支配的恐惧&#xff0c;下意识觉得题目很难 先看 T1&#xff0c;好像不是很难&#xff0c;魔改 Kruskal 应该就行 看 T2 &#xff0c;感觉很神奇&#xff0c;看到多串匹配想到 AC 自动机&#xff0c;又想了想 NOIP …

【开源】基于RMBG的一键抠图与证件照制作系统【含一键启动包】

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

优秀策划人必逛的地方,你不会还不知道吧?

道叔今天依然记得当初刚入行的时候&#xff0c;每天为完成策划任务&#xff0c;焦虑的整晚睡不着觉的痛苦。 但其实……很多时候&#xff0c;选择比努力更重要 优秀的策划和文案&#xff0c;也从来不是天生&#xff0c;你要走的路&#xff0c;前人都已经走过,你要做的仅仅是整…

【计算几何】凸包问题 (Convex Hull)

【计算几何】凸包问题 (Convex Hull) 引言 凸多边形 凸多边形是指所有内角大小都在 [ 0 , π ] [0,π] [0,π]范围内的简单多边形 凸包 在平面上能包含所有给定点的最小凸多边形叫做凸包。 其定义为&#xff1a;对于给定集合 X&#xff0c;所有包含 X 的凸集的交集 S 被称…

QT文件生成可执行的exe程序

将qt项目生成可执行的exe程序可按照以下步骤进行&#xff1a; 1、在qt中构建运行生成.exe文件&#xff1b; 2、从自定义的路径中取出exe文件放在一个单独的空文件夹中&#xff08;exe文件在该文件夹中的release文件夹中&#xff09;&#xff1b; 3、从开始程序中搜索qt&#xf…

Python入门 2024/7/8

目录 数据容器 dict(字典&#xff0c;映射) 语法 定义字典字面量 定义字典变量 定义空字典 从字典中基于key获取value 字典的嵌套 字典的常用操作 新增元素 更新元素 删除元素 清空字典 获取全部的key 遍历字典 统计字典内的元素数量 练习 数据容器的通用操作…

运维锅总详解设计模式

本首先简介23种设计模式&#xff0c;然后用Go语言实现这23种设计模式进行举例分析。希望对您理解这些设计模式有所帮助&#xff01; 一、设计模式简介 设计模式是软件设计中用于解决常见设计问题的一套最佳实践。它们不是代码片段&#xff0c;而是解决特定问题的通用方案。设…

(图文详解)小程序AppID申请以及在Hbuilderx中运行

今天小编给大家带来了如何去申请APPID&#xff0c;如果你是小程序的开发者&#xff0c;就必须要这个id。 申请步骤 到小程序注册页面&#xff0c;注册一个小程序账号 微信公众平台 填完信息后提交注册 会在邮箱收到 链接激活账号 确认。邮箱打开链接后&#xff0c;会输入实…

线程并发库复习

1.进行和线程 什么是进程&#xff1a;进程是内存分配的基本单位&#xff0c;它是程序执行时的一个实例&#xff0c;会被放到进程就绪队列&#xff0c;等进程调度器选择它&#xff0c;给它时间片&#xff0c;它才会运行。在java中启动进程&#xff0c;main&#xff0c;test&…

14-54 剑和诗人28 - 用于实时嵌入查找的向量检索

介绍 LLM 成功的关键因素是向量嵌入的使用。通过将文本转换为数字向量表示&#xff0c;我们可以将语义含义映射到数学向量空间。这使得模型能够根据向量之间的相似性在语言中概括模式。 随着我们的模型和数据集变得越来越大&#xff0c;高效地存储、组织和检索这些嵌入变得至关…

STM32智能交通灯控制系统教程

目录 引言环境准备智能交通灯控制系统基础代码实现&#xff1a;实现智能交通灯控制系统 4.1 数据采集模块 4.2 数据处理与控制算法 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;交通灯管理与优化问题解决方案与优化收尾与总结 1. 引言 智能交通灯控…

【UE5】仅修改结构体的若干个数据

蓝图中的结构体变量 | 虚幻引擎4.27文档 (unrealengine.com) 连线连到傻&#xff0c;因为如果某个变量set空值也一起过去了。一查发现有这个节点。

Kubernetes 为pod指定DNS

在k8s里面&#xff0c;默认创建pod会给pod默认分配一个默认的dns&#xff0c;这个dns是哪来的呢&#xff1f;可不可以改成其他的dns呢&#xff1f; 先进入到pod里面来&#xff0c;可以看到这里面默认设置的DNS服务器&#xff0c;这个服务器地址为10.96.0.10。这个地址是k8s自动…

Qt入门(二):Qt的基本组件

目录 Designer程序面板 1、布局Layout 打破布局 贴合窗口 2、QWidget的属性 3、Qlabel标签 显示图片 4、QAbstractButton 按钮类 按钮组 5、QLineEdit 单行文本输入框 6、ComboBox 组合框 7、若干与数字相关的组件 Designer程序面板 Qt包含了一个Designer程序 &…

【Notepad】Notepad_6.3.1 的中文版安装详情

目录 &#x1f33c;1. Notepad的认识 &#x1f33c;2. Notepad中文版安装详情 &#x1f33c;1. Notepad的认识 Notepad 是 Windows 操作系统中的一个文本编辑器程序&#xff0c;通常用于创建和编辑简单的文本文件&#xff0c;如文本文档 (.txt)。它非常轻量且功能简单&#…

Spring-AOP(二)

作者&#xff1a;月下山川 公众号&#xff1a;月下山川 1、什么是AOP AOP&#xff08;Aspect Oriented Programming&#xff09;是一种设计思想&#xff0c;是软件设计领域中的面向切面编程&#xff0c;它是面向对象编程的一种补充和完善&#xff0c;它以通过预编译方式和运行期…

算法学习笔记(8.2)-动态规划入门进阶

目录 问题判断: 问题求解步骤&#xff1a; 图例&#xff1a; 解析&#xff1a; 方法一&#xff1a;暴力搜索 实现代码如下所示&#xff1a; 解析&#xff1a; 方法二&#xff1a;记忆化搜索 代码示例&#xff1a; 解析&#xff1a; 方法三&#xff1a;动态规划 空间…

全球激光位移传感器市场规模逐渐扩大 企业数量不断增多

全球激光位移传感器市场规模逐渐扩大 企业数量不断增多 位移传感器又称为距离传感器&#xff0c;是用于测量与被测物体之间距离的一种传感器。根据工作原理&#xff0c;位移传感器可以分为超声波位移传感器、红外线位移传感器、激光位移传感器等。其中&#xff0c;激光位移传感…

2024年06月CCF-GESP编程能力等级认证Python编程五级真题解析

本文收录于专栏《Python等级认证CCF-GESP真题解析》&#xff0c;专栏总目录&#xff1a;点这里&#xff0c;订阅后可阅读专栏内所有文章。 一、单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09; 第 1 题 在Python中&#xff0c;print((c for c in “GESP”))的输…

vue实例和容器的一夫一制——04

//准备容器 <div classapp> <h1>{{mag}}</h1> </div> //准备容器 <div classapp> <h1>{{mag}}</h1> </div> //准备容器 <div classapp2> <h1>{{name}}</h1> </div> <script> // 验…