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

责任链模式简介

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

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

        由学生到最上级校长之间一级一级传递,每一级都有自己的下级负责人,当达到阈值,如上图中校长没有下级负责人,此时处理终止。也可能是某个班级自发的购买班服,则上图达到班级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);}@Overridepublic 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);}@Overridepublic 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);}@Overridepublic 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);}
}

        结果如下:

责任链模式优缺点

优点

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

缺点 

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

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

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

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

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

相关文章

python dlib 面部特征点检测

运行环境macos m2芯片 Python 3.11.7,python3.9都能通过,windows系统应该也是一样的效果 import dlib import cv2 import matplotlib.pyplot as plt# Load the image image_path path_to_your_image.jpg # Replace with the path to your image image…

QT 信号和槽 一对多关联示例,一个信号,多个槽函数响应,一个信号源如何绑定多个槽函数

在窗体里放置一个单行文本编辑控件(QLineEdit)、一个标签控件(QLabel)和一个文本浏览控件(QTextBrowser),在单行文 本编辑控件里的文本被编辑时,标签控件和文本浏览控件都会同步显示…

网安速成之选择题(详细解析版)

网安速成之选择题 单选多选 单选 密码学的目的是( C )。 A. 研究数据压缩 B. 研究数据解密 C. 研究数据保密 D. 研究漏洞扫描 密码学的目的是研究数据加密,保证数据的机密性 数据机密性安全服务的基础是( D )。 A. 数…

C++ 的 Tag Dispatching(标签派发) 惯用法

目录 1.概述 2.标准库中的例子 3.使用自己的 Tag Dispatching 3.1.使用 type traits 技术 3.2.使用 Type_2_Type 技术 4.Tag Dispatching的使用场景 5.总结 1.概述 一般重载函数的设计是根据不同的参数决定具体做什么事情,编译器会根据参数匹配的原则确定正确…

面试题 - Java基础个人总结

1、Java语言特点/优势 1.1、什么是面向对象编程 2、Java的八种基本数据类型 2.1、为什么要有基本数据类型的封装类 2.2、Java自动装箱和拆箱 笔试题-1 笔试题-2 2.3、为什么浮点数运行时,会有丢失精度的风险? 2.4、补充知识: 3、重载…

WP All Import插件

使用 WP All Imports 插件并将亚马逊产品集成到 WooCommerce 网站中。在您的网站上,他们可以添加到购物车...然后一旦他们按下结帐,他们就会被发送到亚马逊进行付款 WP All Import 是一个强大的WordPress插件,它允许用户从XML或CSV文件中导入…

封装uview-plus上传组件up-upload,支持v-model绑定

痛点 vue上传组件拿到了一般无法直接使用,需要对其上下传的接口按照业务进行处理及定制。本次拿到的uview-plus也是一样,对其上传组件up-upload进行封装,令其更方便开发 目标 封装希望达到的目标,就是实现v-model的绑定。令其支…

字符串-将str1编辑成str2所需最小代价(hard)

一、题目描述 二、解题思路 该题目使用动态规划的思想来解决问题 刚开始我还在想,删除添加的操作可以等价为替换操作,如果替换操作的Cost大于删除添加组合操作的Cost之和就需要把 rcdcic。 但是在动态规划中,如果对三种不同的操作方式进行…

【Centos7】解决 CentOS 7 中出现 “xx: command not found“ 错误的全面指南

【Centos7】初探xx:command not found解决方案 大家好 我是寸铁👊 【Centos7】解决 CentOS 7 中出现 “xx: command not found” 错误的全面指南✨ 喜欢的小伙伴可以点点关注 💝 前言 经常有小伙伴问我,xx:command not found怎么办&#xff1…

Spring原理-IOC和AOP

概述 在此记录spring的学习内容。spring官网:https://spring.io/ 概念故事 从前,在Java的大森林中,有一片神奇的土地,名叫"Spring"。这片土地上生长着各种美丽而强大的植物,它们分别象征着Spring框架中的…

1.1 寻找灵感:怎样像艺术家一样去看待这个世界

“你是从哪里获取到这些创作灵感的?” 当每一个艺术家被问到这个问题时,只有诚实的艺术家会回答: “这是我偷窃的” 怎样像艺术家一样去看待这个世界呢? 你首先需要弄明白什么是值得你偷窃的,然后你才能继续接下来…

如何在一台电脑上安装多个版本的JDK并且切换使用?

如何在一台电脑上安装多个版本的JDK并且切换使用? 文章目录 如何在一台电脑上安装多个版本的JDK并且切换使用?1.目录管理2.下载JDK3.配置环境变量4. 验证 1.目录管理 我们需要首先对不同版本的JDK进行版本管理,如下所示,我在C盘路…

# linux 系统下 切换 root 用户时出现 authentication failure 的解决办法

linux 系统下 切换 root 用户时出现 authentication failure 的解决办法 1、问题分析: 切换 root 用户时出现 authentication failure,意思即 “身份验证失败”,这是由于新安装的系统,可能没有给 root 用户设置密码。 2、解决方…

算法(二)二分查找

文章目录 二分查找简介实现方式循环方式递归方式 经典例子 二分查找简介 二分查找(binary search)算法,也叫折半算法。二分查找是针对有序的数据集合的查找办法,如果是无序的数据结合就使用遍历。二分查找之所以快速,…

OWASP top10--SQL注入(四、sqlmap安装及使用)

目录 sqlmap工具安装: 工具说明: 主要功能特性包括: 基本使用示例: 先下载python2.7.9版本 sqlmap运行 sqlmap工具使用 -u -r –-levelLEVEL扫描深度级别 --riskRISK 执行测试的风险 -threads 线程数 -batch-smart智能…

鸿蒙开发加强2

快速创建一个符合长度的数组 空数组 Array.from({length: 200}) // 200的长度的空数组 场景:只确定长度,不确定内容的情况 State 状态装饰器 》增强功能 数据变化了 可以引起页面的重新渲染 没有State修饰的变量,不会引起UI的刷新渲染 加…

fintuning chatglm3

chatglm3介绍 ChatGLM3-6B 是 ChatGLM 系列最新一代的开源模型,在保留了前两代模型对话流畅、部署门槛低等众多优秀特性的基础上,ChatGLM3-6B 引入了如下特性: 更强大的基础模型: ChatGLM3-6B 的基础模型 ChatGLM3-6B-Base 采用…

ic基础|时钟篇06:crg到底是什么?一文带你了解crg中的时钟系统!

大家好,我是数字小熊饼干,一个练习时长两年半的ic打工人。我在两年前通过自学跨行社招加入了IC行业。现在我打算将这两年的工作经验和当初面试时最常问的一些问题进行总结,并通过汇总成文章的形式进行输出,相信无论你是在职的还是…

基于Swing和socket实现双向通讯案例

server代码: import javax.swing.*; import java.awt.*; import java.io.*; import java.net.ServerSocket; import java.net.Socket;public class Server extends JFrame {private JTextArea messageArea;private JTextField textField;private PrintWriter write…

像艺术家一样工作:前言

名人名言 “艺术是盗窃” —— 巴勃罗毕加索 “不成熟的诗人模仿,成熟的诗人偷窃;对于偷窃得到的艺术,坏的诗人丑化它,好的诗人加入自己的理解,使它变得更好,至少会让它有点不同。最优秀的诗人&#xff0…