重学设计模式-责任链模式

责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它通过将请求沿着链传递,使多个对象都有机会处理该请求,从而避免了请求的发送者与接收者之间的耦合关系。本文将详细介绍责任链模式的定义、优缺点、应用场景,并通过Java代码展示其实现过程。

一、责任链模式的定义

责任链模式又称为职责链模式,其核心思想是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链。当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。在这种模式下,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,因此责任链将请求的发送者和请求的处理者解耦了。

责任链模式属于对象行为型模式,它主要由以下几个角色组成:

抽象处理者(Handler):定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
具体处理者(Concrete Handler):实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
客户类(Client):创建处理链,并向链头的具体处理者对象提交请求,无需关心处理细节和请求的传递过程。
在这里插入图片描述

二、责任链模式的优缺点

优点
降低了对象之间的耦合度:该模式使得一个对象无须知道到底是哪一个对象处理其请求以及链的结构,发送者和接收者也无须拥有对方的明确信息。
增强了系统的可扩展性:可以根据需要增加新的请求处理类,满足开闭原则。
增强了给对象指派职责的灵活性:当工作流程发生变化时,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。
责任链简化了对象之间的连接:每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if-else 语句。
责任分担:每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
缺点
不能保证每个请求一定被处理:由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响:遍历多个处理者会影响性能,特别是在一些递归调用中。
责任链建立的合理性要靠客户端来保证,增加了客户端的复杂性:可能会由于责任链的错误设置而导致系统出错,如可能会造成循环调用。
三、责任链模式的应用场景
先介绍一下作者实习时用到的,抽奖需要有规则配置,抽奖前和抽奖后都需要进行规则判断,抽奖中规则采用决策树与本文无关不多做赘述,抽奖前首先要判断是否已登录,再判断是否为黑名单,再判断抽奖次数是否达到抽该奖品的要求,等等一系列判断,只要有一个判断失败就返回,这种情况用责任链模式就非常方便,且对后面的增删查改更加友好

责任链模式在多个场景中都有广泛应用,包括但不限于:

公司事务等级制度:一切关于工程的事务必须根据事务重要等级匹配相应职位的人员处理,如果事务重要等级超过该职位设定的处理范围就需要向上级报告,交由上级处理。
Java过滤器:如Netty中的Pipeline和ChannelHandler,Spring Security,Spring AOP,Dubbo Filter过滤器链等。
ERP系统流程审批:如总经理、人事经理、项目经理的审批流程。
权限控制:在网关作为微服务程序的入口,拦截客户端所有的请求实现权限控制,如先判断Api接口限流、黑名单、用户会话、参数过滤等。

四、Java实现责任链模式

下面是一个详细的Java代码示例,展示了如何实现责任链模式。

  1. 定义请求类
    首先,我们需要定义一个请求类,这个请求类包含了我们想要处理的信息。

java代码示例

public class Request {private String message;public Request(String message) {this.message = message;}public String getMessage() {return message;}
}
  1. 定义处理器接口
    接下来,我们定义一个处理器接口,它将规定处理请求的方法。

java代码示例

public interface Handler {void setNext(Handler handler); // 设置下一个处理者void handle(Request request); // 处理请求的方法
}
  1. 实现具体的处理者类
    我们将实现一个或多个具体的处理者类,这些类将实现Handler接口。

java代码示例

// 处理者类 A
public class ConcreteHandlerA implements Handler {private Handler nextHandler;@Overridepublic void setNext(Handler handler) {this.nextHandler = handler;}@Overridepublic void handle(Request request) {if (request.getMessage().equals("A")) {System.out.println("Handler A processed request: " + request.getMessage());} else if (nextHandler != null) {nextHandler.handle(request);}}
}// 处理者类 B
public class ConcreteHandlerB implements Handler {private Handler nextHandler;@Overridepublic void setNext(Handler handler) {this.nextHandler = handler;}@Overridepublic void handle(Request request) {if (request.getMessage().equals("B")) {System.out.println("Handler B processed request: " + request.getMessage());} else if (nextHandler != null) {nextHandler.handle(request);}}
}// 处理者类 C
public class ConcreteHandlerC implements Handler {private Handler nextHandler;@Overridepublic void setNext(Handler handler) {this.nextHandler = handler;}@Overridepublic void handle(Request request) {if (request.getMessage().equals("C")) {System.out.println("Handler C processed request: " + request.getMessage());} else if (nextHandler != null) {nextHandler.handle(request);}}
}
4. 组装责任链并测试
最后,我们需要创建一个类来组合所有处理器,形成一个责任链,并通过调用handle方法测试不同的请求。java
public class ChainOfResponsibility {public static void main(String[] args) {Handler handlerA = new ConcreteHandlerA();Handler handlerB = new ConcreteHandlerB();Handler handlerC = new ConcreteHandlerC();// 设置责任链handlerA.setNext(handlerB);handlerB.setNext(handlerC);// 测试请求Request requestA = new Request("A");Request requestB = new Request("B");Request requestC = new Request("C");Request requestD = new Request("D");// 处理请求handlerA.handle(requestA); // Handler A processed request: AhandlerA.handle(requestB); // Handler B processed request: BhandlerA.handle(requestC); // Handler C processed request: ChandlerA.handle(requestD); // 无任何处理}
}

运行上述代码,你将看到每个请求按照设置的责任链被处理。对应于请求"A"、"B"和"C"的处理结果将被打印出来,而请求"D"则未被处理。

五、责任链模式的变种与扩展

除了上述基本实现外,责任链模式还可以进行变种和扩展,以适应不同的应用场景。

  1. 带有返回值的责任链
    在实际应用中,有时我们希望责任链中的处理者能够返回处理结果。这可以通过修改Handler接口和处理者类的实现来实现。

java代码示例

// 带有返回值的请求处理接口
public interface Handler<T> {void setNext(Handler<T> handler);T handle(Request request);
}// 具体的处理者类A,带有返回值
public class ConcreteHandlerA implements Handler<String> {private Handler<String> nextHandler;@Overridepublic void setNext(Handler<String> handler) {this.nextHandler = handler;}@Overridepublic String handle(Request request) {if (request.getMessage().equals("A")) {return "Handler A processed request: " + request.getMessage();} else if (nextHandler != null) {return nextHandler.handle(request);}return null;}
}// 具体的处理者类B,带有返回值
public class ConcreteHandlerB implements Handler<String> {private Handler<String> nextHandler;@Overridepublic void setNext(Handler<String> handler) {this.nextHandler = handler;}@Overridepublic String handle(Request request) {if (request.getMessage().equals("B")) {return "Handler B processed request: " + request.getMessage();} else if (nextHandler != null) {return nextHandler.handle(request);}return null;}
}// 具体的处理者类C,带有返回值
public class ConcreteHandlerC implements Handler<String> {private Handler<String> nextHandler;@Overridepublic void setNext(Handler<String> handler) {this.nextHandler = handler;}@Overridepublic String handle(Request request) {if (request.getMessage().equals("C")) {return "Handler C processed request: " + request.getMessage();} else if (nextHandler != null) {return nextHandler.handle(request);}return null;}
}// 请求类,包含需要被处理的信息
public class Request {private String message;public Request(String message) {this.message = message;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}
}// 客户端代码,用于测试责任链模式
public class Client {public static void main(String[] args) {// 创建处理者实例Handler<String> handlerA = new ConcreteHandlerA();Handler<String> handlerB = new ConcreteHandlerB();Handler<String> handlerC = new ConcreteHandlerC();// 设置责任链handlerA.setNext(handlerB);handlerB.setNext(handlerC);// 创建请求Request request1 = new Request("A");Request request2 = new Request("B");Request request3 = new Request("C");Request request4 = new Request("D"); // 未知请求,测试链的末尾处理// 处理请求并打印结果System.out.println(handlerA.handle(request1)); // 输出: Handler A processed request: ASystem.out.println(handlerA.handle(request2)); // 输出: Handler B processed request: BSystem.out.println(handlerA.handle(request3)); // 输出: Handler C processed request: CSystem.out.println(handlerA.handle(request4)); // 输出: null(没有处理者处理这个请求)}
}

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

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

相关文章

SuperMap iClient3D for Cesium等高线标注

kele 前言 在三维地形分析中&#xff0c;等高线分析是一种非常重要的分析方法&#xff0c;它能直观的表达出地形的高低起伏特征&#xff0c;在三维系统中受到广泛应用。在SuperMap iClient3D for Cesium中&#xff0c;等高线分析是前端GPU分析&#xff0c;能够分析并渲染出等高…

简易共享屏幕工具改进版

昨天心血来潮写了一篇关于简易共享屏幕工具的文章&#xff0c;发现也有一些阅读量&#xff0c;并且我对于它的效果不是很满意 &#xff0c;实际呈现的帧率还是太低了。所以我今天换了更高效的方式来实现。 50 行代码简易屏幕共享工具 改进 降低分辨率 昨天那个测试的帧率低&a…

4.银河麒麟V10(ARM) 离线安装 MySQL

1. 系统版本 [rootga-sit-cssjgj-db-01u ~]# nkvers ############## Kylin Linux Version ################# Release: Kylin Linux Advanced Server release V10 (Lance)Kernel: 4.19.90-52.39.v2207.ky10.aarch64Build: Kylin Linux Advanced Server release V10 (SP3) /(La…

图像处理-Ch5-图像复原与重建

Ch5 图像复原 文章目录 Ch5 图像复原图像退化与复原(Image Degradation and Restoration)噪声模型(Noise Models)i.i.d.空间随机噪声(Generating Spatial Random Noise with a Specified Distribution)周期噪声(Periodic Noise)估计噪声参数(Estimating Noise Parameters) 在仅…

「下载」智慧园区及重点区域安全防范解决方案:框架统一规划,建设集成管理平台

智慧园区在基础设施建设和管理上仍存在诸多挑战。园区内场景碎片化、系统独立化、数据无交互、应用无联动等问题普遍存在&#xff0c;导致管理效率低下&#xff0c;安全隐患频发。 各安保系统如视频监控系统、报警管理系统、门禁管理系统等独立运行&#xff0c;数据不共享&…

LeetCode - Google 校招100题 第6天 回溯法(Backtracking) (8题)

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/144743505 LeetCode 合计最常见的 112 题: 校招100题 第1天 链表(List) (19题)校招100题 第2天 树(Tree) (21题)校招100题 第3天 动态规划(DP) (20题)

Elasticsearch检索之三:官方推荐方案search_after检索实现(golang)

Elasticsearch8.17.0在mac上的安装 Kibana8.17.0在mac上的安装 Elasticsearch检索方案之一&#xff1a;使用fromsize实现分页 快速掌握Elasticsearch检索之二&#xff1a;滚动查询(scrool)获取全量数据(golang) 1、search_after检索 在前面的文章介绍了fromsize的普通分页…

网易企业邮箱登陆:保障数据安全

网易企业邮箱是一款为企业提供安全可靠的电子邮件服务的工具。通过网易企业邮箱&#xff0c;企业可以实现员工之间的高效沟通和信息共享&#xff0c;同时保障数据的安全性。 企业邮箱的安全性是企业信息保护的重要组成部分。网易企业邮箱采用了多层加密技术&#xff0c;确保邮件…

3.银河麒麟V10 离线安装Nginx

1. 下载nginx离线安装包 前往官网下载离线压缩包 2. 下载3个依赖 openssl依赖&#xff0c;前往 官网下载 pcre2依赖下载&#xff0c;前往Git下载 zlib依赖下载&#xff0c;前往Git下载 下载完成后完整的包如下&#xff1a; 如果网速下载不到请使用网盘下载 通过网盘分享的文件…

Hive其十,优化和数据倾斜

目录 Hive优化 1、开启本地模式 2、explain分析SQL语句 3、修改Fetch操作 4、开启hive的严格模式【提高了安全性】 5、JVM重用 6、分区、分桶以及压缩 7、合理设置map和reduce的数量 合理设置map数量&#xff1a; 设置合理的reducer的个数 8、设置并行执行 9、CBO优…

uniapp通过v-if进行判断时,会出现闪屏?【已解决】

1.问题&#xff1a;按钮切换时&#xff0c;通过v-if来判断&#xff0c;会出现闪烁情况&#xff0c;影响用户体验 2.v-if 闪烁问题可能的原因 ‌条件切换频繁‌&#xff1a;如果 v-if 指令的条件在短时间内频繁切换&#xff0c;会导致元素不断被销毁和重新创建&#xff0c;从而…

ida的使用

一.ida的基本设置 在IDA的安装根目录下有许多文件夹&#xff0c;各个文件夹存储不同的内容 1.目录结构 cfg&#xff1a;包含各种配置文件&#xff0c;基本IDA配置文件ida.cfg,GUI配置文件idagui.cfg&#xff0c;文本模式用户界面配置文件idatui.cfg, idc&#xff1a;包含…

Faster R-CNN

文章目录 摘要Abstract1. 引言2. 框架2.1 RPN2.1.1 网络结构2.1.2 损失函数2.1.3 训练细节 2.2 训练过程 3. 创新点和不足3.1 创新点3.2 不足 参考总结 摘要 Faster R-CNN是针对Fast R-CNN缺点改进的目标检测模型。为了解决候选区域生成耗时长的问题&#xff0c;Faster R-CNN提…

嵌入式AI STM32部署卷积神经网络的魔法棒

基于STM32部署卷积神经网络控制设备方案-AI项目-STM32部署卷积神经网络方案-红外信号复制方案-轨迹识别 项目包含下述内容 硬件部分、PCB制板、BOM表文件等等 (Hardware)外壳、3D打印文件 (3D_print)软件程序、用于电子法棒的软件程序 AI Keil等等(Software)QT上位机动作识别…

GCP Cloud Observability 是什么,有什么使用场景

GCP Cloud Observability 是 Google Cloud Platform (GCP) 提供的一组工具和服务&#xff0c;用于监控、日志记录、追踪和调试应用程序和基础设施的健康和性能。通过收集和分析遥测数据&#xff08;如指标、日志和追踪信息&#xff09;&#xff0c;Cloud Observability 有助于理…

UE4_用户控件_2_按钮的动态效果

效果展示&#xff1a; 操作步骤&#xff1a; 1、新建一个触发Actor&#xff0c;更名为BP_EventTrigger。 这个蓝图类可以拖拽到场景中好多次&#xff0c;生成好多实例。但是我希望每次触发创建的用户控件都是不同的。添加Capsule Collision。 修改胶囊体半高和半径都为156 BP_…

Bert各种变体——RoBERTA/ALBERT/DistillBert

RoBERTa 会重复一个语句10次&#xff0c;然后每次都mask不同的15%token。丢弃了NSP任务&#xff0c;论文指出NSP任务有时甚至会损害性能。使用了BPE ALBERT 1. 跨层参数共享 可以共享多头注意力层的参数&#xff0c;或者前馈网络层的参数&#xff0c;或者全部共享。 实验结果…

ADC(三):注入组的使用

有关ADC的基础知识请参考标准库入门教程 ADC&#xff08;三&#xff09;&#xff1a;注入组的使用 1、规则组软件触发注入组自动注入2、规则组外部触发注入组自动注入3、规则组软件触发注入组外部触发&#xff08;TIM2_CC1&#xff09;4、规则组软件触发注入组外部触发&#xf…

代码随想录算法【Day4】

Day4 1.链表的题目&#xff0c;要在草稿纸上模拟清晰后就简单了 2.双指针更加灵活的应用。 3.环形链表多练习。 24. 两两交换链表中的节点 class Solution { public:ListNode* swapPairs(ListNode* head) {ListNode* _dummyHead new ListNode(0); //虚拟头结点_dummyHead…

(南京观海微电子)——GH7009开机黑屏案例分析

一、 现象描述&#xff1a; 不良现象: LVDS模组&#xff0c;开机大概2秒后就黑屏。 二、问题分析 等主机进入Kernel 后做以下测试&#xff1a; 1、手动reset LCM 后 可以显示正常&#xff1b; 总结&#xff1a; 1&#xff09;uboot 部分HS 太窄&#xff0c;仅有4个clk宽度&am…