设计模式——结构型模式——责任链模式

责任链模式简介

        责任链模式,又名职责链模式,为了避免请求发送者与多个请求处理者耦合在一起将所有请求处理者通过前一对象记住其下一个对象的引用而成一条链;当有请求发生时,可将请求沿着这条链传递,传递过程中每一个对象都对其进行处理,直到达到限定条件不能处理为止。

        举例:学校收取某项费用,此时由底层向上层处理链路可能如下所示:

        由学生到最上级校长之间一级一级传递,每一级都有自己的下级负责人,当达到阈值,如上图中校长没有下级负责人,此时处理终止。也可能是某个班级自发的购买班服,则上图达到班级A就没有下级负责人,责任链终止。

        在现实生活中,常常会出现这样的事例:一个请求有多个对象可以处理,但每个对象的处理条件或权限不同。例如,公司员工请假,可批假的领导有部门负责人、副总经理、总经理等,但每个领导能批准的天数不同,员工必须根据自己要请假的天数去找不同的领导签名,也就是说员工必须记住每个领导的姓名、电话和地址等信息,这增加了难度。这样的例子还有很多,如找领导出差报销、生活中的“击鼓传花”游戏等。

责任链模式结构

  • 抽象处理者(Handler):定义一个处理请求的接口、抽象类,包含一个抽象方法和一个后继连接。
  • 具体处理者(Concrete Handler):实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转发给他的后继者。
  • 客户类(Client):创建处理链,并向链头的具体处理者对象提交请求,不需要关注处理细节和请求的传递过程。 

代码编写

案例简介

        现需要开发一个请假流程控制系统。请假1天(不满1天按一天算)到3天的假只需要小组长同意即可;请假3天到7天的假还需要部门经理同意;请假7天以上的假还需要总经理同意才行。

        类图如下:

代码编写及结果 

  • 定义请假条:
/**
 * 定义请假条
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LeaveRequest {
    // 姓名
    private String name;
    // 请假天数
    private int num;
    // 请假内容
    private String content;
}
  • 定义处理者抽象类(Handler):
/**
 * 处理者抽象类
 */
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 abstract void handlerLeave(LeaveRequest leave);

    // 提交请假条
    public final void submit(LeaveRequest leave){
        if(leave.getNum() == 0){
            return;
        }
        // 如果请假天数达到该领导的处理要求
        if(leave.getNum() >= this.numStart){
            // 该领导处理
            this.handlerLeave(leave);

            // 如果还有上级,并且请假天数超过了当前领导的处理上限
            if(this.nextHandler != null && leave.getNum() > numEnd){
                // 继续提交
                this.nextHandler.submit(leave);
            }else{
                System.out.println("流程结束...");
            }
        }
    }
}
  • 定义处理者实现类(Concrete Handler):
/**
 * 小组长
 */
public class GroupLeader extends Handler{
    public GroupLeader() {
        //小组长处理1-3天的请假
        super(Handler.NUM_ONE, Handler.NUM_THREE);
    }

    @Override
    public void handlerLeave(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
    public void handlerLeave(LeaveRequest leave) {
        System.out.println(leave.getName() + "请假" + leave.getNum() + "天" + ", 请假内容为:" + leave.getContent() + "。");
        System.out.println("部门经理批准...");
    }
}



/**
 * 总经理
 */
public class GeneralManager extends Handler{
    public GeneralManager() {
        super(Handler.NUM_SEVEN);
    }

    @Override
    public void handlerLeave(LeaveRequest leave) {
        System.out.println(leave.getName() + "请假" + leave.getNum() + "天" + ", 请假内容为:" + leave.getContent() + "。");
        System.out.println("总经理批准...");
    }
}
  • 定义测试类(Client):
public class Client {
    public static void main(String[] args) {
        // 定义各位领导及其上级
        GroupLeader groupLeader = new GroupLeader();
        Manager manager = new Manager();
        GeneralManager generalManager = new GeneralManager();
        groupLeader.setNextHandler(manager);
        manager.setNextHandler(generalManager);

        // 定义一个请假条
        LeaveRequest leaveRequest = new LeaveRequest("张三", 42, "身体不适");
        groupLeader.submit(leaveRequest);

    }
}

        结果如下:

责任链模式优缺点

优点

  • 降低对象之间的耦合度:降低了请求发送者和请求接收者之间的耦合度。
  • 增强系统的可扩展性:可以根据需要增加新的请求处理类,满足开闭原则。
  • 增强了给对象指派职责的灵活性:当工作流程发生变化,可以动态的改变链内成员修改它们的次序,也可以动态地新增或删除责任。
  • 简化了对象之间地连接:一个对象只需要保持一个指向其后继者的引用,不需要保持其他处理者的引用。
  • 责任分担:每个类只需要处理自己该处理的工作,不能处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。

缺点 

  • 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。

  • 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。

  • 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。

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

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

相关文章

山东大学软件学院项目实训-创新实训-基于大模型的旅游平台(二十四)- 微服务(4)

目录 8. http客户端Feign 8.1 feign远程调用 8.2 feign自定义配置 8.3 feign性能优化 8.4 feign最佳实践 8. http客户端Feign 8.1 feign远程调用 RestTemplate存在的问题 : 代码可读性差 参数复杂URL难以维护 Feign是声明式的http客户端 使用步骤 &#xf…

03 使用堡塔和xshell

课程的目标 1、理解windows于Linux实现远程通信的过程和所使用的协议SSH 2、熟练使用远程连接工具堡塔和xshell等工具以及SSH和SCP,命令 课程实验 使用堡塔远程并操作centos并实现与windows之间的文件传输 2、使用xshell远程连接并操作centos与windows之间的文…

Day 10:100322. 删除星号以后字典序最小的字符串

Leetcode 100322. 删除星号以后字典序最小的字符串 给你一个字符串 s 。它可能包含任意数量的 ‘’ 字符。你的任务是删除所有的 ’ 字符。 当字符串还存在至少一个 ‘*’ 字符时,你可以执行以下操作: 删除最左边的 ‘*’ 字符,同时删除该星号…

EasyX的安装及使用

Easy X的下载 首先,打开EasyX的官网,点击下载。 下载完成,直接双击文件。点击下一步,直接点击安装,即可安装完成。 Easy X的使用 要使用Easy X,就要在编写代码时,使用头文件,其有两…

自定义注解处理器生成代码

前言 源码中给的几种注解处理器代码都是网上抄的,本文主要是提供了 Maven 源码,不需要自己网上研究爬坑(当然具体生成代码的逻辑还是得自己写)。且从 lombok 抄了可以解决 idea 代理 ProcessingEnvironment 类后所产生的问题。 以下是网上抄的注解处理…

用java实现客服聊天+网络爬虫下载音乐(java网络编程,io,多线程)

一 灵感: 在2022年的暑假,也就是我即将迈进高三的那个暑假,我并没有察觉自己应该要学习了,还是和过往的暑假一样玩着王者荣耀,凌晨2点睡觉,中午12点起床。我依稀记得这种状态一直持续到8月19。然而离开学还…

最全!最新!最细!Redis数据库从入门到应用

#前言: 该博客会详细介绍关于Redis数据库的内容,代码多有注释,最后会讲解如何将Redis应用(以Python与Django为例)。各位的点赞与关注将是小编变强的最大动力。 一、Redis数据库简介: Redis是一个开源的内…

fyne widget小部件2

fyne widget小部件2 form表单 package mainimport ("log""fyne.io/fyne/v2/app""fyne.io/fyne/v2/widget" )func main() {myApp : app.New()myWindow : myApp.NewWindow("Form Widget")entry : widget.NewEntry()textArea : widget.…

Stable Diffusion详细教程

目录 🐋引言 🐋Stable Diffusion基本概念 🦈潜在扩散模型 🦈图像生成原理 🐋Stable Diffusion安装部署 🦈环境要求 🦈安装步骤 🐋Stable Diffusion阶段 🦈准备阶…

正弦、余弦、正切

正弦、余弦、正切这三个概念都是在一个直角三角形这样一个上下文环境里定义的。在一个直角三角形中,斜边叫弦。 正弦(sine) 在一个给定的角θ,它的正弦就是这个角θ对着的直角边与弦的比值,记为sineθ。 余弦&#…

你想让ai干苦力,ai会叫你没脾气(问题实例)

当你想让ai生成的代码直接编译 - 你先要问自己一个直击灵魂的主题:我的修养配得上我的能力吗? 已发现存在需手动修复的问题 - 1/(马大哈)对于sdk理解的不 细致 ,会用基类函数来代替派生类函数; 比如&#…

【kubernetes】探索k8s集群的pod控制器详解(Deployment、StatefulSet、DaemonSet、Job、CronJob)

目录 一、Pod控制器及其功用 二、pod控制器有多种类型 2.1ReplicaSet 2.1.1ReplicaSet主要三个组件组成 2.2Deployment 2.3DaemonSet 2.4StatefulSet 2.5Job 2.6Cronjob 三、Pod与控制器之间的关系 3.1Deployment 3.2SatefulSet 3.2.1StatefulSet三个组件 3.2.2为…

7 款最佳 iPhone 解锁软件和应用程序

在 iOS 上反复失败的解锁尝试可能会导致 iPhone 永久禁用。适当的iPhone解锁器可以帮助恢复您的设备。大多数解锁器的成功率和可靠性都很低。这就是为什么从最好的 iPhone 解锁器中进行选择可以帮助绕过 MDM、删除密码运营商锁定并重新获得 iCloud 访问权限很重要的原因。 7 款…

Windows安装Docker

启用虚拟化 打开 勾选Hyper-V 验证 下载Docker Docker官网 阿里云 安装Docker 傻瓜式安装 遇到问题: 打开命令窗口,执行命令: wsl --update升级完成之后点击Restart按钮即可 切换阿里镜像 https://fmkoym4e.mirror.aliyuncs.com

cocos入门3:新建项目

Cocos Creator 新建项目教程 第一步:启动 Cocos Creator 打开你的计算机,找到并双击 Cocos Creator 的启动图标。如果你尚未安装 Cocos Creator,请首先访问其官方网站(https://www.cocos.com/creator/)下载并安装。 …

使用eclipse自动生成实体类

前言 在软件开发过程中,经常需要创建大量的实体类来映射数据库表或者表示业务模型。手动编写实体类既费时又容易出错,因此许多集成开发环境(IDE)提供了自动生成实体类的功能。本篇博客将介绍如何在 Eclipse 中内置功能来快速生成实…

MyBatis中的接口代理机制及其使用

1. MyBatis中的接口代理机制及其使用 文章目录 1. MyBatis中的接口代理机制及其使用2. 实操2.1 准备工作2.2 insert 增加操作2.3 delete 删除操作2.4 update 修改操作2.5 select 查询一条记录操作2.6 select 查询多条记录操作 3. 总结:4. 最后: MyBatis …

Winddow系统下关于Golang使用Cgo的配置

1.配置CGO_ENABLED为1 go env -w CGO_ENABLED1 2.安装gcc环境,否则出现cgo: C compiler "gcc" not found: exec: "gcc": executable file not found in %PATH%错误 安装包:链接:https://pan.baidu.com/s/1sgF9lijqGeP…

50个常用的Docker命令及如何使用

这里整理了50个常用的Docker命令以及每个命令的使用方法。 docker version:显示Docker版本信息。 示例:docker version docker info:显示Docker系统信息。 示例:docker info docker pull <image>:从Docker Hub下载镜像。 示例:docker pull ubuntu docker run <i…

列表标签 ul+ol/li

04-07、列表标签 ulol/li 概述 列表标签&#xff1a;无序列表ulli、有序列表olli和定义列表 dl dt dd 三种&#xff0c;在网页制作中应用非常广泛&#xff0c;列表就是信息资源的一种展示形式。 特点&#xff1a; 它们都是块元素&#xff0c;可以受到宽度&#xff0c;高度&…