责任链模式 职责链模式 Chain of Responsibility Pattern 行为型 设计模式(十七)

责任链模式(Chain of Responsibility Pattern)
职责链模式
image_5c0e046c_2968

意图

使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系
将这些对象连接成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
责任链模式中,每个对象通过持有对下家的引用而链接起来,形成一条链条,串联起来多个处理对象。
在责任链模式中,请求在链上进行传递,直到链上的某一个对象决定处理此请求。
发出这个请求的客户端程序并不知道到底是哪一个对象具体的处理了请求
这使得系统可以在不影响客户端的情况下,动态的重新组织链和增加责任
比如类加载机制中的双亲委派模型,类加载器含有父  类加载器的引用,形成了一个处理链
(不过类加载机制的具体行为与责任链有出入,会一直委派到最顶级类加载,而不会在中间进行处理然后返回)

解析

责任链模式是一种很常见的场景
比如请假,很多公司会根据请假的原因以及请假的时长,将会有不同的审批人
比如采购,对于采购金额的不同,可能需要不同的审批人
思考下请假的过程,可能你经历过有两种形式:
形式一:
第一步写好请假条;
第二步拿给人事,人事说找部门主管签字
第三步拿请假条给部门主管,部门主管发现请假三天,然后告诉你,一天以上的假期需要老板审批
第四步拿请假条给老板审批
形式二:
第一步写好请假条交给人事;(人事拿给部门主管,部门主管看情况,如果批不了拿给老板审批)
第二步等待审批;
可能的两种流程就是上面这样子的,请假的流程一般就这样子了,总共有几级审批,这几级审批都有谁负责,也不会轻易的变化
再看一个采购审批的例子
示例
以采购为例演示审批流程
抽象处理人角色 处理人拥有姓名属性,另外定义了抽象的操作方法
package nonechainresponsibility;
public abstract class Handler {
protected String name;
Handler(String name){
this.name = name;
}
public abstract void operation();
}

 

具体的处理人角色 DepartmentManager和Boss 
package nonechainresponsibility;
public class DepartmentManager extends Handler {
public DepartmentManager(String name){
super(name);
}
@Override
public void operation() {
System.out.println("DepartmentManager process..name: "+this.name);
}
}
package nonechainresponsibility;
public class Boss extends Handler {
public Boss(String name) {
super(name);
}@Override
public void operation() {
System.out.println("Boss process..name: " + this.name);
}
}
测试代码如下,流程很简单:
如果是金额小于1000元,由部门经理DepartmentManager  李四审批
否则,将由老总 Boss  张三  审批
image_5c0e046c_6677
上面的实例中
测试类Test作为客户端,也就是相当于采购员
需要自行判断金额的范围,然后找对应的审批人进行审批
如果说金额从几百到几万到几十万,根据金额分别有十几个主管负责人进行审批呢?那么审批的逻辑将会变得很复杂
也就是内部将会有更多的选择逻辑判断
而且
如果规则变动了呢?你将不得不修改逻辑,进行调整,显然非常的不利于扩展
即使是新增一个级别的审批,仍旧是需要修改代码逻辑
另外,如果不同的部门的审批顺序略有差异呢?如何应对?
上面的这种处理逻辑的根本问题在于:审批的流程固化在代码中了
可是你只是个采购员,你希望的只是审批单被批准,你其实并不关心到底是谁审批的,那为什么你要关注于这么多的细节呢?
责任链模式就是为了解决这种类似的场景。
一句话概括责任链模式:“能搞就搞,搞不了给下一个人,请求发起者不关心谁帮我处理”

代码示例

处理人角色新增successor 属性,用于作为下游处理,提供了setSuccessor()方法进行设置 
并且对operation方法进行改变,接受参数(Integer price)
package chainresponsibility;
public abstract class Handler {
protected String name;
Handler(String name){
this.name = name;
}
protected Handler successor;
public void setSuccessor(Handler successor){
this.successor = successor;
}
public abstract void operation(Integer price);
}
部门处理人角色和老板角色同步做出修改
将判断逻辑移入到处理内部
如果自己不能处理,那么请求下游进行处理(示例比较简单,所以Boss没搞)
package chainresponsibility;public class DepartmentManager extends Handler {public DepartmentManager(String name){
super(name);
}
@Override
public void operation(Integer price) {
if(price < 1000){
System.out.println("DepartmentManager process..name: "+this.name);
}else{
successor.operation(price);
}
}
}
package chainresponsibility;
public class Boss extends Handler {public Boss(String name) {
super(name);
}@Override
public void operation(Integer price) {
System.out.println("Boss process..name: " + this.name);
}
}
测试代码
package chainresponsibility;
public class Test {
public static void main(String[] args){
/*
* 动态生成链条
* */
Handler DmHandler = new DepartmentManager("李四");
Handler BossHandler = new Boss("张三");
DmHandler.setSuccessor(BossHandler);/*
* 调用处理链的一个起始端点
* */
DmHandler.operation(600);
DmHandler.operation(6000);
}
}

 

image_5c0e046c_872
重构后的代码逻辑没有发生变化---仍旧是处理请求
但是通过引入successor 属性,以及setSuccessor()方法,可以将下游处理者串联起来
拥有了下游的引用,如果处理不了就可以将请求向下传递
因为每个处理者都需要独立面对请求,所以将逻辑内置,也就是条件以参数的形式传递
通过指向下游处理对象的引用,形成了一条链,每次请求只需要请求开始端点位置的对象即可
如果无法处理,会自动请求下游的对象进行处理,客户端不需要关注
而且,通过引用可以在运行期间动态的组织职责链,比如不同部门处理层级不一样的问题就可以轻易解决
如果增加新的审批层级,只需要新增审批类,并且在创建责任链的时候,将新增的审批类添加进去即可
客户端并不需要发生变动
上面的示例简单的演示了职责链模式的演变过程
简单说就是每个人职责清晰的独立划分开来,然后一个模块负责组装生成责任链 
客户端将请求发送给责任链的起始点即可

结构

image_5c0e046c_6dbf
抽象处理者角色Handler
定义一个处理请求的接口
Handler角色知道“下一个处理者”是谁,如果自己无法处理请求,他会将请求转发给“下一个处理者” 
具体的处理者角色ConcreteHandler
处理请求的具体角色,比如上面示例中的DepartmentManager
客户端角色Client
Client角色向组装好的责任链的第一个ConcreteHandler发起请求

通过责任链模式弱化了请求发起者与请求处理者的联系
对于请求者来说,责任链上的所有对象就是一个请求处理者,到底具体到哪个类进行出力,请求者并不关心
不存在“某个请求必须要谁处理”这种明确的指向关系,请求者不清楚
专注于自己的工作
每个处理业务的对象都更加专注于自己的工作,如果自己无法处理,那么交给其他更专业的人
这样则能保障任务能够快速高效的完成
责任链模式并不创建责任链,由系统的其他部分负责创建
示例为了简单所以在测试主函数中一并创建,应该由系统其他部分进行创建,将责任链的连接逻辑与使用解耦
动态改变职责链
引用是组合的形式,可以在运行时动态的设定
上面说到责任链由系统的其他部分进行创建,他可以动态的完成责任链的创建

分类

责任链模式分为纯粹的责任链模式和不纯粹的责任链模式
纯粹的责任链模式要求责任链中的对象,也就是具体的处理者只能在两个行为中选择一个
也就是要么承担责任,要么责任转交给下家
不允许出现某一个具体的处理者对象承担了一部分责任之后又把责任向下传递。
而通常情况下,我们的实际使用的责任链模式很难纯粹,基本都会掺杂一些处理逻辑
其实这种命名与否的争论对于使用模式毫无意义,重点在于解决问题 
黑猫白猫抓到老鼠就是好猫

总结

如果你的系统中已经存在了一个由多个处理者对象组成的请求处理序列
那么你就可以考虑将这个请求处理转换为责任链模式
如果有多于一个处理者对象会处理一个请求,但是事先却并不知道到底谁来处理
这个处理者对象是动态确定的,比如新来一个采购员,他还不熟悉公司规则,不确定到底谁来负责审批他的这个单子
责任链显著的特点就是将请求和处理者进行分离,请求者可以不知道具体是谁处理了请求,将请求与处理进行了解耦,提高了系统的灵活性 
具体的处理者可能还与责任链的组成顺序有很大的关系,通过选择某些处理者组成链,以及设置顺序,增加了极大的灵活性
责任链模式所有的请求都通过责任链进行处理,如果链比较长,而且需求总是在后端进行处理,势必会引入一些性能问题
而且,客户端不知道具体谁处理的,你也不知道,环节较多,调试时也会不方便
而且还需要控制节点的数量,要避免超长链的情况,那样这条链将会变成一种负担,这种会破坏系统的性能  
而且还需要注意,如果一个请求从头走到尾是否一定会有对象对他进行处理?如果没有被处理也可能是因为没有正确的配置责任链而导致的
如果链接生成的有问题,比如环形,并且也没有设置次数限制,岂不是死循环?这些问题都需要在运用时考虑到
对于责任链一句话总结:如果一个请求,可能会被多个处理者中的一个处理,考虑责任链模式
原文地址:责任链模式 职责链模式 Chain of Responsibility Pattern 行为型 设计模式(十七)

 

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

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

相关文章

YOLOv7 在 ML.NET 中使用 ONNX 检测对象

本文介绍如何在 ML.NET 中使用 YOLOv7 的 ONNX 模型来检测图像中的对象。什么是 YOLOYOLO&#xff08;You Only Look Once&#xff09;是一种先进的实时目标检测系统。它是一个在COCO数据集上预训练的物体检测架构和模型系列&#xff0c;其版本也是在不断优化更新。2022年7月&a…

NppFTP小插件的使用

大家在Linux系统中配置运行环境时&#xff0c;一定会遇到相关配置文件的修改&#xff0c;虽说在Linux系统中可以使用vi,vim的命令进行文本编辑&#xff0c;但是操作起来还是没有在Windows系统中用的爽&#xff0c;特别是操作大文本量的文件时。Notepad里提供了一个小插件&#…

『实战』使用Excel催化剂二维码功能批量生成带不同图案二维码。

熟悉Excel催化剂的老读者都知道&#xff0c;每逢图书大促&#xff0c;笔者都会向出版社申请优惠码优惠券来惠及广大粉丝。当然公众号上帮出版社推荐图书&#xff0c;会有佣金回报&#xff0c;这也是笔者唯一能接受的推广方式。公众号自创立以来&#xff0c;没有接过软文&#x…

JavaScriptSerializer类 对象序列化为JSON,JSON反序列化为对象

JavaScriptSerializer 类由异步通信层内部使用&#xff0c;用于序列化和反序列化在浏览器和 Web 服务器之间传递的数据。说白了就是能够直接将一个C#对象传送到前台页面成为javascript对象。要添加System.Web.Extensions.dll的引用。该类位于System.Web.Script.Serialization命…

使用vue组件搭建网页应用

使用vue组件搭建网页应用搭建开发环境开发组件搭建开发环境 搭建一个 vue 项目最快的方式就是使用 vue cli 脚手架进行初始化&#xff0c;包含了所有完整的依赖及开发配置。 首先全局安装 vue cli&#xff0c;打开 cmd 命令提示符 或者 power shell&#xff0c;输入以下命令&…

重新整理 .net core 实践篇 —linux上排查问题实用工具 [外篇]

前言介绍下面几个工具:Lldbcreatedumpdotnet-dumpdotnet-gcdumpdotnet-symbolProcdump该文的前置篇为:https://www.cnblogs.com/aoximin/p/16839812.html献给初学者&#xff0c;这篇就只介绍下看下日志和lldb&#xff0c;毕竟东西太多了。正文我以官网的例子作为演示&#xff1…

Office 365离线安装

Office 365除了可以在线安装外&#xff0c;还可以进行离线安装&#xff0c;但激活还是需要连接互联网的哟首先下载Office部署工具https://www.microsoft.com/en-us/download/details.aspx?id49117 下载文件后&#xff0c;运行自解压缩可执行文件&#xff0c;其中包含 Office 部…

reduceByKey和groupByKey区别与用法

2019独角兽企业重金招聘Python工程师标准>>> 在Spar看中&#xff0c;我们知道一切的操作都是基于RDD的。在使用中&#xff0c;RDD有一种非常特殊也是非常实用的format——pair RDD&#xff0c;即RDD的每一行是&#xff08;key, value&#xff09;的格式。这种格式很…

软件工程的第一性原理丨SmartIDE

作者&#xff1a;徐磊原文地址&#xff1a;https://smartide.cn/zh/blog/2022-1022-software-engineering/徐磊英捷创软科技&#xff08;北京&#xff09;有限公司创始⼈/⾸席架构师 / CEO / SmartIDE开源项⽬创始⼈。微软最有价值专家MVP&#xff0c;微软区域技术总监&#xf…

排序算法之快速排序详解

一、算法介绍 快速排序&#xff1a;快速排序的基本思想是通过一次排序将等待的记录分成两个独立的部分&#xff0c;其中一部分记录的关键字小于另一部分的关键字。C部分的快速排序一直持续到整个序列被排序。 任取一个元素 (如第一个) 为中心提出所有小于它的元素&#xff0c;并…

openstack 中国联盟公开课參会总结

主流趋势 1. openstack defcore 互操作性认证。打通不同的openstack 厂商之间的连接2. 首批OpenStack管理员认证(COA)将于2016年进行3. 混合云应用广泛 Cloud Broker,cascading openstack 云连接器4. DevOps5. 虚拟桌面6. Storage 方面&#xff0c;Ceph和Glusterfs 7. Network…

Re:从零开始的Vue项目搭建

Re&#xff1a;从零开始的Vue项目搭建初始的终结与结束的开始Nodejs项目的简单测试从零开始webpack开发模式webpack编译打包后记初始的终结与结束的开始 最开始接触vue项目搭建是从vue-cli开始&#xff0c;模板式操作&#xff0c;一键搞定&#xff0c;几乎可以无缝进入代码开发…

C# WPF 用代码画一幅图(*精品*)

概述有时候我们的程序界面中需要显示一些简单的示意图&#xff0c;一般我们有原图的话直接嵌入我们程序就可以&#xff0c;但有时候我们没有原图&#xff0c;这时候我们不妨用代码自己画出来.今天小编要给大家展示的是这样一副图片&#xff1a;接下来&#xff0c;我就用代码纯手…

矿难让显卡压了那么多货咋办?NV如是说

2019独角兽企业重金招聘Python工程师标准>>> 在苏州 GTC 开幕的几天前&#xff0c;英伟达刚刚遭遇了一次股价的腰斩。 近来加密货币的热度渐低&#xff0c;受到挖矿热潮照顾许多的英伟达「矿机」销量受到打击&#xff0c;甚至出现了严重的库存危机&#xff0c;加上近…

花式看超级碗 人工智能、大数据在碗里

“超级碗”可不是一个大碗!!!超级碗(Super Bowl)是美国国家美式足球联盟(也称为国家橄榄球联盟)的年度冠军赛&#xff0c;胜者被称为“世界冠军”。超级碗一般在每年1月最后一个或2月第一个星期天举行&#xff0c;那一天称为超级碗星期天(Super Bowl Sunday)。超级碗是比赛的名…

SimMechanics/Second Generation倒立摆模型建立及初步仿真学习

笔者最近捣鼓Simulink&#xff0c;发现MATLAB的仿真模块真的十分强大&#xff0c;以前只是在命令窗口敲点代码&#xff0c;直到不小心敲入simulink&#xff0c;就一发不可收拾。话说simulink的模块化建模确实方便&#xff0c;只要拖拽框框然后双击设置属性就可以慢慢堆建自己的…

10 行代码提取复杂 Excel 数据

把 Excel 文件导入关系数据库是数据分析业务中经常要做的事情&#xff0c;但许多 Excel 文件的格式并不规整&#xff0c;需要事先将其中的数据结构化后再用 SQL 语句写入数据库。而一般情况下&#xff0c;结构化的工作量会比较大&#xff0c;而且很难通用&#xff0c;每次都要针…

人工智能模型的网络结构可视化

本文主要介绍人工智能模型的网络结构可视化的常见方法。对于使用神经网络模型来说&#xff0c;我们主要关注的是模型的输入和输出。在 ML.NET 中使用 ONNX 模型时&#xff0c;我们就需要了解这些信息&#xff0c;以便在构成神经网络的所有层之间生成连接映射。下图就是昨天 《Y…

整理ASP.NET MVC 5各种错误请求[401,403,404,500]的拦截及自定义页面处理实例

http://2sharings.com/2015/asp-net-mvc-5-custom-404-500-error-hanlde https://blog.csdn.net/yhyhyhy/article/details/51003683 ASP.NET MVC 5的开发中&#xff0c;服务器的各种错误[如&#xff1a;401&#xff08;登录授权验证&#xff09;&#xff0c;403&#xff08;禁止…

编辑器领域正发生变革?从面试看 Visual Studio Code 的崛起

Visual Studio Code&#xff08;VS Code&#xff09;的使用率在迅速上升&#xff0c;现在已经成为大多数工程师的首选编辑器&#xff0c;并似乎正迅速抢占其他顶级编辑的市场份额。Triplebyte 每周都会面试数百名工程师。在每次面试中&#xff0c;我们都会记录面试者使用的编辑…