设计模式-责任链模式(Chain of Responsibility)

设计模式-责任链模式(Chain of Responsibility)

    • 一、责任链模式概述
      • 1.1 什么是责任链模式
      • 1.2 简单实现责任链模式
      • 1.3 使用责任链模式的注意事项
    • 二、责任链模式的用途
    • 三、责任链模式实现方式
      • 3.1 基于接口实现责任链模式
      • 3.2 基于抽象类实现责任链模式
      • 3.3 基于匿名内部类实现责任链模式
      • 3.4 基于Lambda表达式实现责任链模式

一、责任链模式概述

1.1 什么是责任链模式

责任链模式是一种面向对象设计模式,该模式中包含了一系列处理对象和命令对象。每个处理对象都有能力决定自己可以处理哪些命令对象,如果遇到无法处理的命令对象,它会将请求传递给下一个处理对象。这种模式的核心在于避免请求发送者与接收者之间的紧密耦合,让多个对象都有可能接收请求,并将这些对象连接成一条链,沿着这条链传递请求,直到有对象处理它为止。

以公司员工请假为例,员工的请假请求可能有多个领导可以批准,但每个领导的批准权限不同。员工需要根据自己要请假的天数去找对应的领导签名。这就是责任链模式的一个生动实例。其实现过程就如同“击鼓传花”游戏,每个参与者都有机会处理事件,但如果无法处理则继续传给下一个人。

在开发中,责任链模式常用于处理复杂数据处理和校验的场景。通过使用责任链模式,可以将一个请求的处理过程分解为一系列的处理对象,使得代码更加清晰、灵活和易于维护。

1.2 简单实现责任链模式

首先,我们定义一个抽象的处理类(Handler):

public abstract class Handler {protected Handler nextHandler;public void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}public abstract void handleRequest(String request);
}

然后,我们创建具体的处理类(ConcreteHandler),它们继承自抽象的处理类,并实现了handleRequest方法:

public class ConcreteHandlerA extends Handler {@Overridepublic void handleRequest(String request) {if (request.equals("A")) {System.out.println("ConcreteHandlerA处理了请求:" + request);} else if (nextHandler != null) {nextHandler.handleRequest(request);} else {System.out.println("没有处理器可以处理该请求:" + request);}}
}public class ConcreteHandlerB extends Handler {@Overridepublic void handleRequest(String request) {if (request.equals("B")) {System.out.println("ConcreteHandlerB处理了请求:" + request);} else if (nextHandler != null) {nextHandler.handleRequest(request);} else {System.out.println("没有处理器可以处理该请求:" + request);}}
}

然后,我们创建具体的处理类(ConcreteHandler),它们继承自抽象的处理类,并实现了handleRequest方法:

public class ConcreteHandlerA extends Handler {@Overridepublic void handleRequest(String request) {if (request.equals("A")) {System.out.println("ConcreteHandlerA处理了请求:" + request);} else if (nextHandler != null) {nextHandler.handleRequest(request);} else {System.out.println("没有处理器可以处理该请求:" + request);}}
}public class ConcreteHandlerB extends Handler {@Overridepublic void handleRequest(String request) {if (request.equals("B")) {System.out.println("ConcreteHandlerB处理了请求:" + request);} else if (nextHandler != null) {nextHandler.handleRequest(request);} else {System.out.println("没有处理器可以处理该请求:" + request);}}
}

最后,我们在客户端代码中创建处理器对象,并将它们连接起来:

public class Client {public static void main(String[] args) {Handler handlerA = new ConcreteHandlerA();Handler handlerB = new ConcreteHandlerB();handlerA.setNextHandler(handlerB);handlerA.handleRequest("A"); // 输出:ConcreteHandlerA处理了请求:AhandlerA.handleRequest("B"); // 输出:ConcreteHandlerB处理了请求:BhandlerA.handleRequest("C"); // 输出:没有处理器可以处理该请求:C}
}

这样,我们就实现了一个简单的责任链模式。当客户端发送一个请求时,它会沿着责任链传递,直到找到一个可以处理该请求的处理器。

1.3 使用责任链模式的注意事项

  • 1、存在循环调用的风险。在实现责任链模式时,可能存在节点之间的循环调用,从而形成死循环。这种循环调用的风险通常出现在两种情况下:一是责任链节点自身会对请求进行多次处理;二是责任链节点之间相互调用。为了避免这种情况,需要对责任链节点的处理逻辑进行严格的控制和规范,确保节点的处理逻辑只能一次性地对请求进行处理,并且不会出现相互调用的情况。另外,可以通过设置最大处理次数或者设置超时时间等机制来防止出现死循环,从而避免对系统的影响。

  • 2、确定责任链的顶端和底端。在实现责任链模式时,需要确定责任链的顶端和底端,以确保请求能够被正确地传递和处理。

  • 3、避免请求发送者与接收者之间的紧密耦合关系。在责任链模式中,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,这样可以降低系统的耦合度。

  • 4、注意性能问题。由于每个处理器都需要处理请求和传递请求,因此使用责任链模式可能会导致系统性能下降。为了解决这个问题,可以考虑使用异步处理等方式来提高系统的性能。

二、责任链模式的用途

责任链模式主要用于处理那些需要经过多个处理步骤或处理者才能完成的请求。其主要应用场景包括:

  • 1、过滤器模式:例如在Java Web应用中,过滤器链用于对HTTP请求和响应进行处理。每个过滤器负责处理特定的任务,然后将请求传递给下一个过滤器。这种场景下,责任链模式可以有效地解耦每个过滤器的处理逻辑。

  • 2、事件处理模式:在图形用户界面编程中,事件处理通常采用责任链模式。例如在一个按钮上,可能有多个监听器(如点击、鼠标移动等),每个监听器负责处理一种特定的事件。当事件发生时,会沿着监听器链进行传递,直到有监听器处理该事件为止。

  • 3、工作流引擎:在企业级应用中,工作流引擎通常使用责任链模式来处理复杂的业务流程。每个处理节点负责处理流程中的特定步骤,然后将工作项传递给下一个处理节点。

  • 4、权限设计:在权限设计中,可以使用责任链模式来实现权限验证。例如,一个用户可能需要经过多个角色的权限验证,每个角色负责验证一部分权限。这样既可以实现权限验证的逻辑分离,又可以提高系统的灵活性和扩展性。

三、责任链模式实现方式

3.1 基于接口实现责任链模式

首先,我们需要定义一个处理请求的接口,然后创建具体的处理器类实现该接口。最后,在客户端代码中,我们将处理器对象链接在一起,形成一个责任链。

以下是一个简单的Java实现:

定义处理请求的接口:

public interface RequestHandler {void setNextHandler(RequestHandler nextHandler);void handleRequest(String request);
}

创建具体的处理器类实现该接口:

public class ConcreteHandlerA implements RequestHandler {private RequestHandler nextHandler;@Overridepublic void setNextHandler(RequestHandler nextHandler) {this.nextHandler = nextHandler;}@Overridepublic void handleRequest(String request) {if (request.startsWith("A")) {System.out.println("ConcreteHandlerA处理了请求:" + request);} else if (nextHandler != null) {nextHandler.handleRequest(request);} else {System.out.println("没有处理器可以处理该请求:" + request);}}
}public class ConcreteHandlerB implements RequestHandler {private RequestHandler nextHandler;@Overridepublic void setNextHandler(RequestHandler nextHandler) {this.nextHandler = nextHandler;}@Overridepublic void handleRequest(String request) {if (request.startsWith("B")) {System.out.println("ConcreteHandlerB处理了请求:" + request);} else if (nextHandler != null) {nextHandler.handleRequest(request);} else {System.out.println("没有处理器可以处理该请求:" + request);}}
}

在客户端代码中,将处理器对象链接在一起,形成一个责任链:

public class Client {public static void main(String[] args) {RequestHandler handlerA = new ConcreteHandlerA();RequestHandler handlerB = new ConcreteHandlerB();handlerA.setNextHandler(handlerB);handlerA.handleRequest("A1");handlerA.handleRequest("B1");handlerA.handleRequest("C1");}
}

运行客户端代码,输出结果如下:

ConcreteHandlerA处理了请求:A1
ConcreteHandlerB处理了请求:B1
没有处理器可以处理该请求:C1

3.2 基于抽象类实现责任链模式

要实现基于抽象类的责任链模式,首先需要创建一个抽象类,然后创建具体的处理器类继承自抽象类。最后在客户端代码中,将处理器对象链接在一起,形成一个责任链。以下是一个简单的示例:

创建一个抽象类Handler:

public abstract class Handler {protected Handler nextHandler;public void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}public abstract void handleRequest(String request);
}

创建具体的处理器类ConcreteHandlerA和ConcreteHandlerB,分别继承自Handler:

public class ConcreteHandlerA extends Handler {@Overridepublic void handleRequest(String request) {if (request.equals("A")) {System.out.println("ConcreteHandlerA处理了请求:" + request);} else {if (nextHandler != null) {nextHandler.handleRequest(request);} else {System.out.println("没有处理器可以处理该请求:" + request);}}}
}public class ConcreteHandlerB extends Handler {@Overridepublic void handleRequest(String request) {if (request.equals("B")) {System.out.println("ConcreteHandlerB处理了请求:" + request);} else {if (nextHandler != null) {nextHandler.handleRequest(request);} else {System.out.println("没有处理器可以处理该请求:" + request);}}}
}

在客户端代码中,将处理器对象链接在一起,形成一个责任链:

public class Client {public static void main(String[] args) {Handler handlerA = new ConcreteHandlerA();Handler handlerB = new ConcreteHandlerB();handlerA.setNextHandler(handlerB);handlerA.handleRequest("A");handlerA.handleRequest("B");handlerA.handleRequest("C");}
}

运行客户端代码,输出结果如下:

ConcreteHandlerA处理了请求:A
ConcreteHandlerB处理了请求:B
没有处理器可以处理该请求:C

3.3 基于匿名内部类实现责任链模式

public interface Handler {void setNextHandler(Handler nextHandler);void handleRequest(String request);
}public class ConcreteHandlerA implements Handler {private Handler nextHandler;@Overridepublic void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}@Overridepublic void handleRequest(String request) {if ("A".equals(request)) {System.out.println("ConcreteHandlerA处理了请求:" + request);} else if (nextHandler != null) {nextHandler.handleRequest(request);} else {System.out.println("没有处理器可以处理该请求:" + request);}}
}public class ConcreteHandlerB implements Handler {private Handler nextHandler;@Overridepublic void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}@Overridepublic void handleRequest(String request) {if ("B".equals(request)) {System.out.println("ConcreteHandlerB处理了请求:" + request);} else if (nextHandler != null) {nextHandler.handleRequest(request);} else {System.out.println("没有处理器可以处理该请求:" + request);}}
}public class Client {public static void main(String[] args) {Handler handlerA = new ConcreteHandlerA();Handler handlerB = new ConcreteHandlerB();handlerA.setNextHandler(handlerB);handlerA.handleRequest("A");handlerA.handleRequest("B");handlerA.handleRequest("C");}
}

3.4 基于Lambda表达式实现责任链模式

责任链模式是一种行为设计模式,它允许多个对象处理一个请求,从而避免了请求的发送者和接收者之间的耦合关系。在Java中,我们可以使用Lambda表达式和接口来实现责任链模式。

首先,我们需要定义一个处理器接口,该接口包含一个处理方法:

public interface Handler {void handleRequest(String request);
}

接下来,我们可以创建具体的处理器类,实现这个接口:

public class ConcreteHandlerA implements Handler {private Handler nextHandler;@Overridepublic void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}@Overridepublic void handleRequest(String request) {if (request.equals("A")) {System.out.println("ConcreteHandlerA处理了请求:" + request);} else if (nextHandler != null) {nextHandler.handleRequest(request);} else {System.out.println("没有处理器可以处理该请求:" + request);}}
}public class ConcreteHandlerB implements Handler {private Handler nextHandler;@Overridepublic void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}@Overridepublic void handleRequest(String request) {if (request.equals("B")) {System.out.println("ConcreteHandlerB处理了请求:" + request);} else if (nextHandler != null) {nextHandler.handleRequest(request);} else {System.out.println("没有处理器可以处理该请求:" + request);}}
}

最后,我们可以使用Lambda表达式来创建处理器对象,并设置责任链:

public class Main {public static void main(String[] args) {Handler handlerA = new ConcreteHandlerA();Handler handlerB = new ConcreteHandlerB();handlerA.setNextHandler(handlerB);handlerA.handleRequest("A");handlerA.handleRequest("B");handlerA.handleRequest("C");}
}

运行上述代码,输出结果如下:

ConcreteHandlerA处理了请求:A
ConcreteHandlerB处理了请求:B
没有处理器可以处理该请求:C

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

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

相关文章

解决Jenkins执行git脚本时报错:No such device or address问题

问题现象: Jenkins执行BeanShell脚本时,报错:jenkins fatal: could not read Username for http://112.11.120.1: No such device or address 解决方案: 解决服务器拉取git仓库的代码权限,使用高级子模块克隆功能。…

深入解析 Redis 分布式锁原理

一、实现原理 1.1 基本原理 JDK 原生的锁可以让不同线程之间以互斥的方式来访问共享资源,但如果想要在不同进程之间以互斥的方式来访问共享资源,JDK 原生的锁就无能为力了。此时可以使用 Redis 来实现分布式锁。 Redis 实现分布式锁的核心命令如下&am…

投票助手图文音视频礼物打赏流量主小程序开源版开发

投票助手图文音视频礼物打赏流量主小程序开源版开发 图文投票:用户可以发布图文投票,选择相应的选项进行投票。 音视频投票:用户可以发布音视频投票,观看音视频后选择相应的选项进行投票。 礼物打赏:用户可以在投票过…

cpu 支持内存带宽与内存最大长度的关系《鸟哥的 Linux 私房菜》

鸟哥的 Linux 私房菜 -- 计算机概论 -- 計算机:辅助人脑的好工具 同理,64 位 cpu 一次接受内存传递的 64bit 数据,内存字节地址用 64 位记录,最多能记录2^64个字节2^64Bytes2^34GB17179869184GB2^24TB,理论上&#xff…

Java后端开发——JDBC入门实验

JDBC(Java Database Connectivity)是Java编程语言中用于与数据库建立连接并进行数据库操作的API(应用程序编程接口)。JDBC允许开发人员连接到数据库,执行各种操作(如插入、更新、删除和查询数据&#xff09…

计算机考研408有多难?25考研经验贴,开个好头很有必要

前言 大家好,我是陈橘又青,相信关注我的各位小伙伴们中,大多都是在计算机专业的大学生吧! 每天都有许多人在后台私信我,问我要不要考研,我想说这个东西是因人而异的,像我本人就选择了就业&…

基于公共业务提取的架构演进——外部依赖防腐篇

1.背景 有了前两篇的帐号权限提取和功能设置提取的架构演进后,有一个问题就紧接着诞生了,对于诸多业务方来说,关键数据源的迁移如何在各个产品落地? 要知道这些数据都很关键: 对于帐号,获取不到帐号信息是…

如何像专家一样高效使用搜索引擎?适用于百度Baidu、谷歌Google

你几乎可以在互联网上搜索到任何内容,而Google是大多数人选择搜索信息的主要途径之一。 尽管频繁地使用Google,但是大部分互联网用户都不知道如何快速和高效地使用Google搜索。 可以说使用Google是一门艺术。 想要获得正确的答案,你需要提出正确的问题。想要快速地获得正…

【ElasticSearch系列-07】ES的开发场景和索引分片的设置及优化

ElasticSearch系列整体栏目 内容链接地址【一】ElasticSearch下载和安装https://zhenghuisheng.blog.csdn.net/article/details/129260827【二】ElasticSearch概念和基本操作https://blog.csdn.net/zhenghuishengq/article/details/134121631【三】ElasticSearch的高级查询Quer…

简单好看个人引导页毛玻璃页面 HTML 源码

毛玻璃个人引导页源码,界面简洁,已测可完美搭建,UI非常不错的,有兴趣的自行去安装体验吧,其它就没什么好介绍的了。 学习资料源代码:百度网盘 请输入提取码:ig8c

读程序员的制胜技笔记08_死磕优化(上)

1. 过早的优化是万恶之源 1.1. 著名的计算机科学家高德纳(Donald Knuth)的一句名言 1.2. 原话是:“对于约97%的微小优化点,我们应该忽略它们:过早的优化是万恶之源。而对于剩下的关键的3%,我们则不能放弃优化的机会。” 2. 过早…

适合汽车音频系统的ADAU1977WBCPZ、ADAU1978WBCPZ、ADAU1979WBCPZ四通道 ADC,24-bit,音频

一、ADAU1977WBCPZ 集成诊断功能的四通道ADC,音频 24 b 192k IC,SPI 40LFCSP ADAU1977集成4个高性能模数转换器(ADC),其直接耦合输入具有10 V rms性能。该ADC采用多位Σ-Δ架构,其连续时间前端能够实现低EMI性能。它可以直接连接…

11.9存储器实验总结(单ram,双ram,FIFO)

实验设计 单端口RAM实现 双端口RAM实现 FIFO实现 文件结构为

npm install 安装总结

npm install moduleName 会把moduleName 包安装到node_modules目录中不会修改package.json之后运行npm install命令时,不会自动安装moduleName npm install moduleName -g 安装模块到全局,不会在项目node_modules目录中保存模块包。不会将模块依赖写入de…

python-jupyter实现OpenAi语音对话聊天

1.安装jupyter 这里使用的是jupyter工具,安装时需要再cmd执行如下命令,由于直接执行pip install jupyter会很慢,咱们直接使用国内源 pip install --user jupyter -i http://pypi.tuna.tsinghua.edu.cn/simple/ --trusted-host pypi.tuna.t…

Python按类别和比例从Labelme数据集中划分出训练数据集和测试数据集

Python按类别和比例从Labelme数据集中划分出训练数据集和测试数据集 前言前提条件相关介绍实验环境按类别和比例从Labelme数据集中划分出训练数据集和测试数据集代码实现输出结果 前言 由于本人水平有限,难免出现错漏,敬请批评改正。更多精彩内容&#x…

Kotlin与Java写法的变更

目录 获取类的Java Class属性 类型检查 for循环 switch语句 if判断 获取类的Java Class属性 //Java Intent intent new Intent(this, MainActivity.class);//Kotlin val intent Intent(this, MainActivity::class.java) 类型检查 //Java apple instanceof Fruit !(app…

真正解决jellyfin硬解码转码

前段时间入手一个DS423集成显卡UHD600,搭了一个jellyfin,发现网上关于硬解码的教程基本都存在问题,没有真正解决我的硬解码问题。经过一系列分析修改,最终实现硬解码。先贴效果图: 下载安装jellyfin这里就不叙述&#…

Maven-构建生命周期与插件

一、概念和基础 Maven针对项目的构建和发布定义了一系列明确的步骤,根据作用不同这些步骤分属于不同的生命周期。Maven针对每个步骤都有对应的默认插件,Maven在构建过程中是通过调用这些插件完成整个过程的。开发者只需要通过简单的命令就可以驱动maven…

若依分离版——使用Knife4j 自动生成接口文档

背景: 前后端分离程序,如果需要前端开发人员和后端开发人员配合开发,则需要将接口文档并显性给前端人员 解决办法: 使用knife4j替代若依自带的swagger,因为knife4j是在swagger基础上包装的,Knife4j不仅具…