责任链模式 (Chain of Responsibility Pattern)
定义
责任链模式是一种行为型设计模式,用于在对象间建立一条处理请求的链。它允许多个对象有机会处理请求,从而减少请求的发送者和接收者之间的耦合。在责任链模式中,每个接收者包含对另一个接收者的引用,形成一条链。如果一个对象不能处理请求,它会将请求传递给链中的下一个对象,直至链的末端。
责任链模式由多个处理器(或接收者)组成,每个处理器决定自己是否处理请求或将其传递给链上的下一个处理器。这种模式实现了发送者和接收者之间的解耦,同时允许动态地调整链中的处理器。
责任链模式主要包含以下两个角色:
- 处理器(Handler):
- 定义了处理请求的接口或抽象类,并通常持有对下一个处理器的引用。在其子类中,它可以选择处理请求或将请求传递给链上的下一个对象。
- 具体处理器(Concrete Handler):
- 实现处理器接口的具体类。每个具体处理器决定它是否要处理请求,如果不处理,则将请求传递给链中的下一个对象。
解决的问题
- 请求的发送者和接收者解耦:
- 在没有责任链模式的情况下,请求的发送者需要知道哪个接收者能够处理该请求,并直接调用相应的处理方法。责任链模式使得请求的发送者不需要直接与具体的接收者交互,从而解耦了发送者和接收者。
- 动态处理请求:
- 责任链模式允许动态地重新组织和分配责任链上的处理者。这意味着可以在运行时改变请求的处理顺序或者增加新的处理者。
- 简化对象间的连接:
- 通过责任链,可以减少对象间复杂的条件语句。在责任链模式中,请求沿着链传递,直到被处理。这避免了显式的多重条件判断。
- 增加处理者的灵活性:
- 责任链模式让每个处理者都有机会处理请求。处理者可以决定是否处理请求,或者将请求传递给链上的下一个对象。
- 分布式责任:
- 责任链模式允许多个对象处理请求,而不是只有一个对象负责所有的情况。这种分布式责任有助于代码的复用和扩展。
使用场景
- 多个对象可以处理同一个请求,但具体的处理者在运行时才确定:
- 当一个请求可能由多个不同的对象处理,但是具体由哪个对象处理在运行时才决定时,责任链模式是理想的解决方案。
- 请求的发送者不需要知道是谁处理了请求:
- 如果请求的发送者不需要知道请求最终由哪个对象处理,责任链模式可以将请求的发送和处理解耦。
- 动态指定一组对象处理请求:
- 当需要动态地指定一系列对象来处理请求时,责任链模式提供了一种灵活的方法来组织这些对象。
- 实现不同方式的请求处理:
- 在有多种处理方式,并且希望根据请求的类型或条件以不同的方式处理时,责任链模式能够提供足够的灵活性。
示例代码1-日志处理器
// 抽象处理器类
public abstract class Logger {public static int INFO = 1;public static int DEBUG = 2;public static int ERROR = 3;protected int level;protected Logger nextLogger;public void setNextLogger(Logger nextLogger) {this.nextLogger = nextLogger;}public void logMessage(int level, String message) {if (this.level <= level) {write(message);}if (nextLogger != null) {nextLogger.logMessage(level, message);}}abstract protected void write(String message);
}// 具体处理器实现
class ConsoleLogger extends Logger {public ConsoleLogger(int level) {this.level = level;}@Overrideprotected void write(String message) { System.out.println("Standard Console::Logger: " + message);}
}// 客户端使用责任链
public class ChainPatternDemo {private static Logger getChainOfLoggers() {Logger errorLogger = new ErrorLogger(Logger.ERROR);Logger fileLogger = new FileLogger(Logger.DEBUG);Logger consoleLogger = new ConsoleLogger(Logger.INFO);errorLogger.setNextLogger(fileLogger);fileLogger.setNextLogger(consoleLogger);return errorLogger;}public static void main(String[] args) {Logger loggerChain = getChainOfLoggers();loggerChain.logMessage(Logger.INFO, "This is an information.");loggerChain.logMessage(Logger.DEBUG, "This is a debug level information.");loggerChain.logMessage(Logger.ERROR, "This is an error information.");}
}
示例代码2-审批流程
// 抽象处理器
abstract class Approver {protected Approver successor;public void setSuccessor(Approver successor) {this.successor = successor;}public abstract void processRequest(PurchaseRequest request);
}// 具体处理器:经理
class Manager extends Approver {public void processRequest(PurchaseRequest request) {if (request.getAmount() < 1000) {System.out.println("Manager will approve the request of " + request.getAmount());} else if (successor != null) {successor.processRequest(request);}}
}// 具体处理器:总监
class Director extends Approver {public void processRequest(PurchaseRequest request) {if (request.getAmount() < 5000) {System.out.println("Director will approve the request of " + request.getAmount());} else if (successor != null) {successor.processRequest(request);}}
}// 具体处理器:CEO
class CEO extends Approver {public void processRequest(PurchaseRequest request) {if (request.getAmount() < 10000) {System.out.println("CEO will approve the request of " + request.getAmount());} else {System.out.println("Request of " + request.getAmount() + " needs a board meeting!");}}
}// 请求类
class PurchaseRequest {private double amount;public PurchaseRequest(double amount) {this.amount = amount;}public double getAmount() {return amount;}
}// 客户端代码
public class ChainOfResponsibilityDemo {public static void main(String[] args) {Approver manager = new Manager();Approver director = new Director();Approver ceo = new CEO();manager.setSuccessor(director);director.setSuccessor(ceo);manager.processRequest(new PurchaseRequest(500));manager.processRequest(new PurchaseRequest(1500));manager.processRequest(new PurchaseRequest(5500));}
}
主要符合的设计原则
- 开闭原则(Open-Closed Principle):
- 责任链模式允许在不修改现有代码的情况下添加新的处理器。你可以添加新的处理类来扩展系统的功能,而无需修改现有的处理链或客户端代码。因此,系统对扩展是开放的,但对修改是封闭的。
- 单一职责原则(Single Responsibility Principle):
- 在责任链模式中,每个处理器只负责处理特定类型的请求。这符合单一职责原则,因为每个处理器类只有一个理由发生变化——处理其特定的请求。
- 里氏替换原则(Liskov Substitution Principle):
- 责任链中的处理器通常遵循相同的接口。这意味着处理器的任何子类都可以替换其父类,而不影响系统的行为。
在JDK中的应用
- java.util.logging.Logger:
- 在
java.util.logging包中,Logger类使用责任链模式。日志消息可以在一个日志处理链中传递,每个处理器(如ConsoleHandler,FileHandler)决定是否处理日志消息,并将消息传递到链中的下一个处理器。
- 在
- Java Servlet Filters:
- 在Java Servlet API中,过滤器(Filter)使用责任链模式。请求和响应在多个过滤器之间传递,每个过滤器可以独立地处理请求或响应,或将其传递给链中的下一个过滤器。
- javax.servlet.FilterChain:
FilterChain是Servlet API的一部分,它允许多个过滤器按顺序处理HTTP请求和响应。每个过滤器在链中都有机会处理请求和响应,或将其传递给链上的下一个过滤器。
在Spring中的应用
- Spring Security的过滤器链:
- 在Spring Security中,安全过滤器链是责任链模式的一个显著例子。请求通过一系列的安全过滤器,每个过滤器执行特定的安全检查(如认证、授权等)。这些过滤器可以自定义和配置,形成一个处理安全的责任链。
- Spring Web的拦截器:
- 在Spring MVC中,拦截器(Interceptor)提供了一种在处理HTTP请求时插入自定义逻辑的机制。拦截器可以形成一个拦截器链,每个拦截器按顺序执行,处理请求或响应,或将控制权传递给链中的下一个拦截器。
- Spring AOP的通知链:
- 在Spring的面向切面编程(AOP)中,通知(Advice)可以被看作是责任链的一部分。不同的通知(如前置通知、后置通知、环绕通知等)可以按顺序应用于方法调用,形成一个通知链。
相关文章:
责任链模式 (Chain of Responsibility Pattern)
定义 责任链模式是一种行为型设计模式,用于在对象间建立一条处理请求的链。它允许多个对象有机会处理请求,从而减少请求的发送者和接收者之间的耦合。在责任链模式中,每个接收者包含对另一个接收者的引用,形成一条链。如果一个对…...
企业营销管理能够实现自动化吗?怎么做?
当今企业面临着越来越多的营销难题:如何有效培育潜在客户、如何提高营销活动的效果、如何优化营销资源的分配......企业的营销管理怎么做?或许CRM系统营销自动化会起到作用。 客户细分: 企业可以通过CRM的客户细分功能,根据客户…...
【数据结构】什么是栈?
🦄个人主页:修修修也 🎏所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 📌栈的定义 📌元素进栈出栈的顺序 📌栈的抽象数据类型 📌栈的顺序存储结构 📌栈的链式存储结构 链栈的进…...
基于C#实现鸡尾酒排序(双向冒泡排序)
通俗易懂点的话,就叫“双向冒泡排序”。 冒泡是一个单向的从小到大或者从大到小的交换排序,而鸡尾酒排序是双向的,从一端进行从小到大排序,从另一端进行从大到小排序。 从图中可以看到,第一次正向比较,我们…...
CentOS添加开机启动
1.编写项目启动脚本(run.sh) #!/bin/bash-切换到程序所在路径 cd /home/cavs_install/app/cavs-admin/target/ # 等待其他组件启动完毕后再启动本项目(如果不需要等待,本步骤可省略) sleep 300 # 实际启动命令 nohup …...
SpringCloudAlibaba之Nacos的持久化和高可用——详细讲解
目录 一、Nacos持久化 1.持久化说明 2.安装mysql数据库5.6.5以上版本(略) 3.修改配置文件 二、nacos高可用 1.集群说明 2.nacos集群架构图 2.集群搭建注意事项 3.集群规划 4.搭建nacos集群 5.安装Nginx 6.配置nginx conf配置文件 7.启动nginx进行测试即可 一、Nacos持久…...
vue3安装eslint和prettier,最简单的步骤
第1步: 安装eslint yarn add eslint -D 第2步: 在根文件夹中,创建.eslintrc.js文件 第3步: 在package.json文件中新增命令 "lint": "eslint --fix --ext .ts,.tsx,.vue src --quiet","prettier"…...
Day32| Leetcode 122. 买卖股票的最佳时机 II Leetcode 55. 跳跃游戏 Leetcode 45. 跳跃游戏 II
Leetcode 122. 买卖股票的最佳时机 II 题目链接 122 买卖股票的最佳时机 II 本题目设计的还是比较巧妙的,把最终的利润分为每天的利润就解决了(贪心),每天的利润就是前一天买进,后一天卖出,转化到代码上就…...
95.STL-遍历算法 for_each
算法概述: 算法主要是由头文件 <algorithm> <functional> <numeric> 组成。 <algorithm> 是所有STL头文件中最大的一个,范围涉及到比较、 交换、查找、遍历操作、复制、修改等等 <numeric> 体积很小,只包括几个在序列上面…...
Python基础语法之学习type()函数
Python基础语法之学习type函数 一、代码二、效果 查看数据类型或者说查看变量存储的数据类型 一、代码 print(type("文本")) print(type(666)) print(type(3.14))二、效果 梦想是生活的指南针,坚持追逐梦想,终将抵达成功的彼岸。不要害怕失败…...
filebeat报错dropping too large message of size
filebeat报错: dropping too large message of size 1714620. 原因: kafka对每一条消息的大小进行了限制。 解决 kafka端 修改config/server.properties,添加以下配置 max_message_bytes10000000 replica.fetch.max.bytes10000000修改…...
【C++】类型转换 ④ ( 子类 和 父类 之间的类型转换 - 动态类型转换 dynamic_cast )
文章目录 一、子类 和 父类 之间的类型转换 - 动态类型转换 dynamic_cast1、构造父类和子类2、子类 和 父类 之间的类型转换 - 隐式类型转换3、子类 和 父类 之间的类型转换 - 静态类型转换 static_cast4、子类 和 父类 之间的类型转换 - 重新解释类型转换 reinterpret_cast5、…...
在CentOS 7.9上搭建高性能的FastDFS+Nginx文件服务器集群并实现外部远程访问
文章目录 引言第一部分:FastDFS介绍与安装1.1 FastDFS简介1.2 FastDFS安装1.2.1 安装Tracker Server1.2.2 安装Storage Server 1.3 FastDFS配置1.3.1 配置Tracker Server1.3.2 配置Storage Server1.3.3 启动FastDFS服务 第二部分:Nginx配置2.1 Nginx安装…...
YOLOv8独家原创改进: AKConv(可改变核卷积),即插即用的卷积,效果秒杀DSConv | 2023年11月最新发表
💡💡💡本文全网首发独家改进:可改变核卷积(AKConv),赋予卷积核任意数量的参数和任意采样形状,为网络开销和性能之间的权衡提供更丰富的选择,解决具有固定样本形状和正方形的卷积核不能很好地适应不断变化的目标的问题点,效果秒殺DSConv 1)AKConv替代标准卷积进行…...
Docker pause/unpause命令
docker pause :暂停容器中所有的进程。 docker unpause :恢复容器中所有的进程。 语法 docker pause CONTAINER [CONTAINER...]docker unpause CONTAINER [CONTAINER...]实例 暂停数据库容器db01提供服务。 docker pause db01恢复数据库容器db01提供…...
PostgreSQL create or replace view和重建视图 有什么区别?
一、 replace vs 重建 遇到开发提了个问题,create or replace view和重建视图(dropcreate)有什么区别,查询资料整理了一下。 1. create or replace 当存在同名视图时,尝试将其替换新视图语句必须与现有视图查询具有相…...
Selenium 连接到现有的 Firefox 示例
当前环境: python 3.7 selenium 3.14.1 urllib3 1.26.8 Frefox 115.1.0esr(32位) geckodriver.exe 0.33.0 1 下载 Firefox 浏览器,根据自己的需要选择。 下载 Firefox 浏览器,这里有简体中文及其他 90 多种语言版本…...
小程序如何进行版本回退
当商家决定回退小程序版本时,可能是因为新版本出现了一些问题或者不符合预期,需要恢复到之前的稳定版本。下面具体介绍怎么回退小程序的版本。 在小程序管理员后台->版本设置处,点击版本回退。确认后,小程序会回退到上一次的版…...
15:00面试,15:06就出来了,问的问题有点变态。。。
从小厂出来,没想到在另一家公司又寄了。 到这家公司开始上班,加班是每天必不可少的,看在钱给的比较多的份上,就不太计较了。没想到8月一纸通知,所有人不准加班,加班费不仅没有了,薪资还要降40%…...
大数据-之LibrA数据库系统告警处理(ALM-37008 MPPDB服务不可用)
告警解释 告警模块每30秒周期性检测MPPDB服务健康状态,当检测到MPPDB健康状态为“故障”时产生告警。 当检测到MPPDB健康状态为“良好”时告警恢复。 告警属性 告警ID 告警级别 可自动清除 37008 致命 是 告警参数 参数名称 参数含义 ServiceName 产生…...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
淘宝扭蛋机小程序系统开发:打造互动性强的购物平台
淘宝扭蛋机小程序系统的开发,旨在打造一个互动性强的购物平台,让用户在购物的同时,能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机,实现旋转、抽拉等动作,增…...
书籍“之“字形打印矩阵(8)0609
题目 给定一个矩阵matrix,按照"之"字形的方式打印这个矩阵,例如: 1 2 3 4 5 6 7 8 9 10 11 12 ”之“字形打印的结果为:1,…...
鸿蒙HarmonyOS 5军旗小游戏实现指南
1. 项目概述 本军旗小游戏基于鸿蒙HarmonyOS 5开发,采用DevEco Studio实现,包含完整的游戏逻辑和UI界面。 2. 项目结构 /src/main/java/com/example/militarychess/├── MainAbilitySlice.java // 主界面├── GameView.java // 游戏核…...
Canal环境搭建并实现和ES数据同步
作者:田超凡 日期:2025年6月7日 Canal安装,启动端口11111、8082: 安装canal-deployer服务端: https://github.com/alibaba/canal/releases/1.1.7/canal.deployer-1.1.7.tar.gz cd /opt/homebrew/etc mkdir canal…...
GeoServer发布PostgreSQL图层后WFS查询无主键字段
在使用 GeoServer(版本 2.22.2) 发布 PostgreSQL(PostGIS)中的表为地图服务时,常常会遇到一个小问题: WFS 查询中,主键字段(如 id)莫名其妙地消失了! 即使你在…...
