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

news2025/4/10 19:22:31

文章目录

    • 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);
    }

    @Override
    protected 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);
    }

    @Override
    protected 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);
    }

    @Override
    protected 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会继续将异常向上抛出,直到被处理为止。

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

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

相关文章

CocosCreator实战篇 | 实现刮刮卡和橡皮擦 | 擦除效果

📢博客主页:https://blog.csdn.net/dxt19980308 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! 📢本文由肩匣与橘编写,首发于CSDN🙉 📢生活依旧是美好而…

【SSM框架】spring的创建与使用

spring的创建与使用Spring项目的创建创建一个maven项目添加Spring依赖添加启动类将bean存储到Spring 中创建bean对象将bean对象存储到Spring容器中从Spring中获取bean创建Spring(上下文)对象从Spring中获取到bean对象使用Bean(非必须)从spring中获取Bean…

奇瑞版Model 3与Model Y登场:正式进军高端纯电

作者 | Amy 编辑 | 德新4月7日,奇瑞在北京举办「新能源之夜」。整场发布会都在传递一个讯息:奇瑞搞新能源,要大搞特搞! 奇瑞在这场发布会上,对新能源的战略、技术、品牌和产品作了全面梳理。其中最引人注目的是&#x…

环信web、uniapp、微信小程序sdk报错详解---注册篇(二、三)

项目场景: 记录对接环信sdk时遇到的一系列问题,总结一下避免大家再次踩坑。这里主要针对于web、uniapp、微信小程序在对接环信sdk时遇到的问题。 注册篇(二) 注册用户报错400 原因分析: 从console控制台输出及network请求返回入手分析 可以看…

【三十天精通Vue 3】第十一天 Vue 3 过渡和动画详解

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

Java 集合框架面试问题集锦

Java集合框架(例如基本的数据结构)里包含了最常见的Java常见面试问题。很好地理解集合框架,可以帮助你理解和利用Java的一些高级特性。下面是面试Java核心技术的一些很实用的问题。 Q:最常见的数据结构有哪些,在哪些场…

telnet远程管理linux主机及Zlib、openssl、openssh升级

目录 一、telnet远程管理主机 1、检查是否安装telnet 2、安装telnet服务 3、测试telnet登录 二、zlib、openssl、openssh升级 1、下载zlib包 2、下载openssl包 3、下载openssh包 4、 编译安装zlib 5、编译安装openssl 6、准备升级openssh环境 ①注意必须使用telne…

LLM 快人一步的秘籍 —— Zilliz Cloud,热门功能详解来啦!

最近,我们发布了可处理十亿级向量数据的 Zilliz Cloud GA 版本,为用户提供开箱即用的向量数据库服务,大大降低了数据库的运维成本。 看过上一篇文章《可处理十亿级向量数据!Zilliz Cloud GA 版本正式发布》的朋友们知道&#xff0…

【SSM】Spring6(十.面向切面编程AOP)

文章目录1.AOP2. AOP的七大术语3. 切点表达式4.使用Spring的AOP4.1 环境准备4.2 基于AspectJ的AOP注解式开发步骤4.3 所有通知类型4.4 切面顺序4.5 通用切点4.6 获取目标方法的方法签名4.7 全注解式开发4.8 基于XML配置的AOP5. 案例:事务处理1.AOP 将与核心业务无关…

Visual Studio Code跳转到CSS定义

Visual Studio Code 快速跳转到 VUE文件 或 CSS文件的定义位置(跳转到class定义,跳转到css定义),插件Css Peek、Vue Peek 对提升开发效率上,事半功倍。 目录 1、跳转到CSS定义 1.1、CSS Peek 1.2、Vue Peek 2、其他…

舌体胖瘦的自动分析-曲线拟合-或许是最简单判断舌形的方案(六)

返回至系列文章导航博客 1 简介 在中医智能舌诊项目中需要舌体胖瘦的自动分析 舌体胖瘦是中医诊断中重要的观察依据,。胖大舌“舌色淡白,舌体胖嫩,比正常舌大而厚,甚至充满口腔”,主脾肾阳虚,气化失常&am…

C++无符号整型与有符号整型变量的运算-不简单

示例分析&#xff1a; #include<iostream> #include <stdio.h>struct Result {char c;char d;unsigned char e; };Result getChar(int x, int y) {Result res;unsigned int a x;(a y > 10) ? (res.c 1) : (res.c 2);res.d a y;res.e a y;return res; …

RHCE第一次作业at和cront两个任务管理程序的区别

1.at 单一执行的例行性工作&#xff1a;仅处理执行一次就结束了 -m 当任务完成之后&#xff0c;即使没有标准输出&#xff0c;将给用户发送邮件 -l atq的别名&#xff0c;可列出目前系统上面的所有该用户的at调度 -d atrm的别名,可以取消一个在at调度中的工作 -v 使用较明显的…

基于html+css的图片展示11

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

信息安全保障人员CISAW认证基础级、专业级通用认证条件

信息安全保障人员认证&#xff08;Certified Information Security Assurance Worker&#xff0c;简称“CISAW”&#xff09;是中国网络安全审查技术与认证中心针对信息安全保障领域不同专业技术方向、应用方向和保障岗位&#xff0c;依据国际标准ISO/IEC 17024《人员认证机构通…

HTTPS-TSL握手

HTTP一般基于TCP协议&#xff0c;而HTTPS就是在这之间加了SSL/TLS协议&#xff0c;那么在TCP三次握手建立TCP连接后&#xff0c;就需要TLS握手建立SSL/TLS连接。 TLS握手-流程 &#xff08;基于RSA算法&#xff09; &#xff08;1&#xff09;首先&#xff0c;客户端向服务器发…

Unity快手上手【熟悉unity编辑器,C#脚本控制组件一些属性之类的】

Unity学习参考文档和开发工具 ☺ unity的官网文档&#xff1a;https://docs.unity3d.com/cn/current/Manual/ScriptingSection.html ■ 学习方式&#xff1a; 首先了解unity相关概述&#xff0c;快速认识unity编辑器&#xff0c;然后抓住重点的学&#xff1a;游戏对象、组件|…

【C++】1. 命名空间

文章目录一、命名空间的由来二、命名空间的使用2.1 关键字&#xff1a;namespace2.2 访问命名空间里的标识符2.3 命名空间的特点三、总结一、命名空间的由来 当我们使用c语言编写项目时&#xff0c;可能遇到以下情况&#xff1a; 变量名与某个库函数名重复&#xff0c;导致保…

sscanf和snprintf格式化时间字符串的日期与时间戳相互转换用法

sscanf格式化时间字符串的用法 UTC&#xff1a;Coordinated Universal Time 协调世界时。因为地球自转越来越慢&#xff0c;每年都会比前一年多出零点几秒&#xff0c;每隔几年协调世界时组织都会给世界时1秒&#xff0c;让基于原子钟的世界时和基于天文学&#xff08;人类感知…

测试技术与信号处理实验报告

目录 金属箔式应变片——单臂电桥性能实验 金属箔式应变片——半桥性能实验 金属箔式应变片——全桥性能实验 差动变压器的性能实验 直流全桥的应用——电子秤实验 交流激励时霍尔式传感器的位移特性实验 电容式传感器的位移实验 磁电式转速传感器测速实验 金属箔式应变…