小侃设计模式(十四)-职责链模式

news2024/11/19 4:44:45

1.概述

责任链模式(Chain of Responsibility Pattern)是为请求创建了一个接收者对象的链,让请求沿着这条链进行传播,直到有对象处理它为止,它属于典型的行为型模式。这种方式降低了发送者和处理者之间的耦合关系,使多个对象都有机会处理请求。
责任链模式的使用场景很多,例如Struts2中的拦截器,SpringMVC中的HandlerExecutionChain等。本文将分析责任链的原理及使用,帮助大家更好地理解。

2.原理及使用

2.1 原理

责任链模式的类图如下:
在这里插入图片描述
责任链包含的核心角色如下:

抽象处理者角色(Handler):定义一个处理请求的接口,包含抽象处理方法和设置后继连接者方法;
具体处理者(HandlerA、HandlerB):实现抽象处理者处理方法的具体类,判断能否处理本次请求,如果可以则直接处理,不可以则将请求传给后继者;
处理链创建类(ChainOfHandler):创建处理链,并向链首的处理者提交请求,它不关心处理细节和请求的传递过程。

2.2 案例

有一个高校资源审批流程,加入采购最小单位是学院,当采购金额小于1万时,院长审批即可;当金额大于1万且小于2万时,需要学校财政处处长审批;当金额大于2万且小于3万时,需要副校长进行审批;当金额大于3万时,需要校长审批。

传统处理方式如下:
在这里插入图片描述

通过定义一个审批接口Approval,院长、财政处处长、副校长、校长分别实现该接口中的approve()方法,实现审批流程。客户端会关联具体的采购类Purchase,该类包含采购具体用品及总价,在Client类中,调用Purchase类的getTotalPrice()方法获取总价后,需要编写如下代码:

        Purchase purchase = new Purchase();
        double totalPrice = purchase.getTotalPrice();
        Dean dean = new Dean();
        FinanceMaster financeMaster = new FinanceMaster();
        VicePrincipal vicePrincipal = new VicePrincipal();
        SchoolMaster schoolMaster = new SchoolMaster();

        if (totalPrice > 0 && totalPrice < 10000) {
            dean.approve();
        } else if (totalPrice >= 10000 && totalPrice < 20000) {
            financeMaster.approve();
        } else if (totalPrice >= 20000 && totalPrice < 30000) {
            vicePrincipal.approve();
        } else if (totalPrice >= 30000) {
            schoolMaster.approve();
        }

上述代码中需要在if…else…语句中判断,根据采购总价来选择不同的人去审批。这种方式的缺陷在于如果各个级别的人员审批金额发生变化或者审批人员发生变化,客户端必须做出相应的改变,造成了一种强耦合关系,不利于代码维护和扩展。
采用责任链模式进行改造,结果如下:
在这里插入图片描述
编码如下:

public interface Approval {

    void approve(Double totalPrice);

    void setNext(Approval approval);
}



public class Dean implements Approval {

    private Double totalPrice;

    private Approval approval;

    public Dean(Double totalPrice) {
        this.totalPrice = totalPrice;
    }


    @Override
    public void approve(Double price) {
        if (price > 0 && price < totalPrice) {
            System.out.println("院长开始审批---------");
            System.out.println("院长审批通过---------");
        } else {
            if (approval != null) {
                approval.approve(price);
            } else {
                System.out.println("无人能够处理");
            }
        }
    }

    @Override
    public void setNext(Approval approval) {
        this.approval = approval;
    }
}




public class FinanceMaster implements Approval {

    private Double totalPrice;

    private Approval approval;

    public FinanceMaster(Double totalPrice) {
        this.totalPrice = totalPrice;
    }

    @Override
    public void approve(Double price) {
        if (price >= 10000 && price < totalPrice) {
            System.out.println("财政处处长开始审批---------");
            System.out.println("财政处处长审批通过---------");
        } else {
            if (approval != null) {
                approval.approve(price);
            } else {
                System.out.println("无人能够处理");
            }
        }
    }

    @Override
    public void setNext(Approval approval) {
        this.approval = approval;
    }
}



public class VicePrincipal implements Approval {

    private Double totalPrice;

    private Approval approval;

    public VicePrincipal(Double totalPrice) {
        this.totalPrice = totalPrice;
    }


    @Override
    public void approve(Double price) {
        if (price >= 20000 && price < totalPrice) {
            System.out.println("副校长开始审批---------");
            System.out.println("副校长审批通过---------");
        } else {
            if (approval != null) {
                approval.approve(price);
            } else {
                System.out.println("无人能够处理");
            }
        }
    }

    @Override
    public void setNext(Approval approval) {
        this.approval = approval;
    }
}

public class SchoolMaster implements Approval {

    private Double totalPrice;

    private Approval approval;

    public SchoolMaster(Double totalPrice) {
        this.totalPrice = totalPrice;
    }

    @Override
    public void approve(Double price) {
        if (price >= 30000) {
            System.out.println("校长开始审批---------");
            System.out.println("校长审批通过---------");
        } else {
            if (approval != null) {
                approval.approve(price);
            } else {
                System.out.println("无人能够处理");
            }
        }
    }

    @Override
    public void setNext(Approval approval) {
        this.approval = approval;
    }
}


import lombok.Data;

@Data
public class Purchase {

    /**
     * 采购类型
     */
    private Integer type;

    /**
     * 采购数量
     */
    private Integer number;

    /**
     * 采购物品名称
     */
    private String name;

    /**
     * 采购物品总价
     */
    private Double totalPrice;


}


public class ChainOfHandler {

    private static Purchase purchase = new Purchase();

    /**
     * 校长审批的类型为4,也就是总价小于10000
     */
    private static Dean dean = new Dean(10000.0);

    /**
     * 校长审批的类型为3,也就是总价大于等于10000,小于20000
     */
    private static FinanceMaster financeMaster = new FinanceMaster(20000.0);

    /**
     * 校长审批的类型为2,也就是总价大于等于20000,小于30000
     */
    private static VicePrincipal vicePrincipal = new VicePrincipal(30000.0);

    /**
     * 校长审批的类型为1,也就是总价大于30000
     */
    private static SchoolMaster schoolMaster = new SchoolMaster(30000.0);

    public static void setChain() {
        dean.setNext(financeMaster);
        financeMaster.setNext(vicePrincipal);
        vicePrincipal.setNext(schoolMaster);
    }

    public static void main(String[] args) {
        purchase.setName("桌子采购");
        purchase.setNumber(500);
        purchase.setTotalPrice(50000.0);
        purchase.setType(1);

        setChain();

        dean.approve(purchase.getTotalPrice());
    }
}

运行结果如下:

在这里插入图片描述
如果设置总金额为50000,得到如下结果:
在这里插入图片描述

2.3 责任链的优势与缺点

2.3.1 优势

1、降低了耦合度,它将请求的发送者和接收者解耦;
2、简化了对象,使得调用者不需要知道链的内部结构;
3、符合开闭原则,当给对象增加新的职责时,只需在新增一个具体子链类,调整一下内部链结构即可;
4、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。

2.3.2 缺点

1、不能保证请求一定会被链路处理;
2、代码调试时过于复杂,可能会造成循环调用;
3、可能不容易观察运行时的特征,有碍于除错;
4、当链路过长时,会极大影响系统的性能。

2.3.3 注意事项

1、当使用责任链时,需要控制链的长度,避免出现超长链的情况;
2、需要考虑不被链路处理的请求返回情况。

3.小结

1.责任链将请求与处理分开,实现解耦,提高系统的灵活性;
2.简化了对象,使对象不需要知道链路结构;
3.责任链在使用时,需要考虑链路长度情况,避免链路过长,它的主要使用场景是多个对象处理同一个请求,内部有大量逻辑判断。

4.参考文献

1.《设计模式之禅》-秦小波著
2.《大话设计模式》-程杰著
3.https://www.bilibili.com/video/BV1G4411c7N4-尚硅谷设计模式

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

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

相关文章

HTML+CSS简单的网页制作期末作业 关于我的家乡——四川文化网页介绍 DW大学生网页作业制作设计 Dreamweaver简单网页成品

家乡旅游景点网页作业制作 网页代码运用了DIV盒子的使用方法&#xff0c;如盒子的嵌套、浮动、margin、border、background等属性的使用&#xff0c;外部大盒子设定居中&#xff0c;内部左中右布局&#xff0c;下方横向浮动排列&#xff0c;大学学习的前端知识点和布局方式都有…

chapter1——亚稳态的世界

目录1.亚稳态理论2.亚稳态窗口3.计算MTBF4.避免亚稳态多级同步器时钟倍频电路的多级同步器5.亚稳态测试电路6.同步器类型7.综合性建议在异步系统中&#xff0c;由于数据和时钟的关系不是固定的&#xff0c;因此有时会出现违反建立和保持时间的现象&#xff0c;此时便会输出介于…

OTA: Optimal Transport Assignment for Object Detection原理与代码解读

paper&#xff1a;OTA: Optimal Transport Assignment for Object Detection code&#xff1a;https://github.com/Megvii-BaseDetection/OTA 背景 标签分配&#xff08;Label Assignment&#xff09;是目标检测中重要的一环&#xff0c;经典的标签分配策略采用预定义的规则…

Type-challehges learning: pick

type-challenges/README.zh-CN.md at main TIMPICKLE/type-challenges GitHub 最近真的是迷上了type-challenges。无法自拔 TS真是太香了&#xff01; 今天手写一个pick 从类型定义的属性中&#xff0c;选取指定一组属性&#xff0c;返回一个新的类型定义。 type Pick<T…

Npm——发布依赖库并使用

1. 注册一个NPM账号 npm官方地址&#xff1a;https://www.npmjs.com/ 2. 在本地创建一个目录,输入npm初始化命令&#xff0c;并修改package.json,创建src/index.js入口文件 npm init --yespackage.json name npm发布时的包名&#xff0c;和已有的npm库不能重复version 包版本…

网络安全——SQL注入之安全狗bypass深度剖析

作者名&#xff1a;Demo不是emo 主页面链接&#xff1a;主页传送门 创作初心&#xff1a;舞台再大&#xff0c;你不上台&#xff0c;永远是观众&#xff0c;没人会关心你努不努力&#xff0c;摔的痛不痛&#xff0c;他们只会看你最后站在什么位置&#xff0c;然后羡慕或鄙夷座…

这些调试API技巧你熟悉吗?

通常&#xff0c;我们在调试第三方提供的API时&#xff0c;有时候并没那么顺畅&#xff0c;甚至可能本身就是API服务有问题&#xff0c;但是需要提供你结论的"依据"。下面整理了一些API调试技巧&#xff0c;也方便你甩锅 简单来说分为以下两点 检测状态信息检测返回…

MySQl(八):索引机制

MySQl&#xff1a;索引索引概述索引结构B树的演变过程B树Hash索引分类聚集索引和二级索引### 回表查询思考索引语法普通索引联合索引删除索引索引使用索引使用规则之验证索引效率索引使用规则之最左前缀法则索引使用规则之索引失效情况索引使用规则之SQL提示索引使用规则之覆盖…

java多线程

最近看了寒食君的java多线程的教程&#xff0c;感觉深受启发&#xff0c;做个笔记以后方便回忆。 寒食君的个人空间-寒食君个人主页-哔哩哔哩视频 java多线程 什么是线程模型? JVM线程与操作系统线程之间存在着某种映射关系&#xff0c;这两种不同维度的线程之间的规范和协…

SpringCloud微服务(十)——Hystrix服务降级熔断限流

Hystrix服务降级熔断限流 SpringCloud&#xff0c;已停更 前言 分布式系统面临的问题&#xff0c;复杂分布式体系结构中的应用程序&#xff0c;有数10个依赖关系&#xff08;feign调用&#xff09;, 每个依赖关系在某些时候将不可避免地失败。低耦合就是微服务之间关系少。当…

pytorch初学笔记(十):神经网络基本结构之最大池化的使用

目录 一、最大池化&#xff1a;下采样 1.1 参数介绍 1.2 公式 二、最大池化的作用和目的 三、代码实战 3.1 题目要求 3.2 池化的具体实现 3.2.1 步骤 3.2.2 报错及其原因 3.2.3 ceil_mode不同运行的结果不同 3.2.4 完整代码 3.3 tensorboard可视化 一、最大池化&…

【强化学习论文合集】AAMAS-2022 强化学习论文 | 2022年合集(三)

强化学习(Reinforcement Learning, RL),又称再励学习、评价学习或增强学习,是机器学习的范式和方法论之一,用于描述和解决智能体(agent)在与环境的交互过程中通过学习策略以达成回报最大化或实现特定目标的问题。 本专栏整理了近几年国际顶级会议中,涉及强化学习(Rein…

相控阵天线(六):直线阵列特殊综合方法(变形泰勒综合法、贝利斯综合法、伍德沃德抽样法)

目录简介变形泰勒综合法贝利斯综合法伍德沃德-劳森抽样法配相抵消法简介 阵列天线的综合问题是其分析的逆问题&#xff0c;即是在预先给定辐射特性(如方向图形状、副瓣电平等)的情况下&#xff0c;综合出阵列激励幅度和相位。其中特殊综合主要包括&#xff1a;左右副瓣电平不相…

关于Idea合并不同分支代码你怎么看

一、环境说明 1. IDEA版本 2020.1 2. git版本 2.33.0 二、整体合并 1. 软件开发中&#xff0c;在一次版本迭代过程中&#xff0c;大家可能会在同一个开发分支dev进行开发&#xff0c;同时开发不同功能 &#xff0c;开发完以后需要自行合并到测试分支test&#xff0c;交给测试…

Feign高级实战-源码分析

目录参考导读什么是FeignFeign 和 Openfeign 的区别OpenFeign的启动原理在启动类申明EnableFeignClientsregisterDefaultConfigurationregisterFeignClientsregisterFeignClientgetTarget()创建一个代理对象HttpClientFeignLoadBalancerConfigurationOpenFeign 的工作原理动态代…

多策略协同改进的阿基米德优化算法及其应用(Matlab代码实现)

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

论文阅读:On the User Behavior Leakage from Recommender System Exposure

论文地址 Motivation&#xff1a; 现阶段对于用户行为的保护仅仅从用户端来考虑&#xff0c;比如用户的行为数据等。然而推荐系统是一个闭环的过程&#xff0c;即用户交互了物品&#xff0c;推荐系统根据用户的交互信息去推荐物品&#xff0c;用户也会根据推荐系统推荐的物品做…

[Java] 浅析rpc的原理及所用到的基本底层技术

文章目录前言阅读前须知rpc是什么&#xff1f;别的进程 vs 别的机器rpc的目的或是我们为什么需要rpc&#xff1f;实现rpc所涉及到的底层技术1. 通信技术&#xff08;网络IO、Network IO&#xff09;套接字&#xff08;Socket&#xff09;bio、nio与Netty2. 网络协议&#xff08…

【仿真建模】第三课:AnyLogic入门基础课程 - 多层建筑行人疏散仿真讲解

文章目录一、Agent类的概念二、行人疏散仿真2.1 仿真模型示意图2.2 具体实现步骤一、Agent类的概念 二、行人疏散仿真 2.1 仿真模型示意图 2.2 具体实现步骤 首先&#xff0c;新建模型 新建一个MyFloor1对象&#xff0c;代表第一个楼层 创建矩形墙&#xff0c;并放到原点…

专业数采软件DXP OPC Server售后问题解决方案

DeviceXPlorer OPC Server是一套实现工业自动化设备数据读取或发送的软件。它提供与制造车间中的控制设备&#xff08;如 PLC、机床和机器人&#xff09;的连接&#xff0c;支持200多种设备通讯协议&#xff0c;便捷的配置&#xff0c;快速实现设备联网采集。 在与设备通讯方面…