Spring框架之责任链模式 (Chain of Responsibility Pattern)

news2024/11/14 12:50:45

责任链模式(Chain of Responsibility Pattern)详解

责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,旨在将请求的发送者和处理者解耦。它通过创建一条 处理请求的责任链,使得多个对象都有机会处理请求,从而避免了请求的发送者和处理者之间的紧耦合。责任链模式的核心思想是将请求沿着链传递,直到有一个对象处理它为止。

在责任链模式中,处理请求的对象(处理者)被组织成一个链条,链中的每个对象都负责对请求进行处理。如果当前对象不能处理请求,它将把请求传递给链中的下一个对象,直到请求被处理为止。

1. 责任链模式的定义

1.1 什么是责任链模式?

责任链模式通过将一系列的处理对象组成一条链,使得每个处理对象都有机会去处理请求。每个处理对象都包含指向下一个处理对象的引用,如果当前处理对象无法处理请求,它会将请求传递给链中的下一个对象,直到请求被某个处理对象处理为止。

1.2 责任链模式的关键思想
  • 解耦请求发送者和请求处理者:请求的发送者并不直接知道具体由哪个处理者来处理请求,而是通过一条链来传递请求。
  • 动态地调整请求的处理顺序:可以灵活地改变责任链中处理者的顺序,甚至可以动态地添加新的处理者。
  • 每个处理者只关心自己能处理的请求:如果某个处理者无法处理请求,它将把请求传递给链中的下一个处理者。

2. 责任链模式的结构

责任链模式通常由以下角色构成:

  1. Handler(处理者):定义了一个接口或抽象类,声明了处理请求的方法,并持有对下一个处理者的引用。
  2. ConcreteHandler(具体处理者):实现了 Handler 接口,并定义了如何处理请求。如果当前处理者不能处理请求,它会将请求传递给链中的下一个处理者。
  3. Client(客户端):负责创建链并将请求传递给责任链的第一个处理者。
类图
    +------------------+        
    |    Handler       |        
    +------------------+        
    | + handleRequest()|        
    | + setNextHandler()|        
    +------------------+        
           ^                    
           |                    
    +------------------------+   
    | ConcreteHandlerA       |  
    +------------------------+  
    | + handleRequest()      |  
    | + setNextHandler()     |  
    +------------------------+   
           ^                    
           |                    
    +------------------------+   
    | ConcreteHandlerB       |  
    +------------------------+  
    | + handleRequest()      |  
    | + setNextHandler()     |  
    +------------------------+   
           ^                    
           |                    
    +------------------------+   
    | ConcreteHandlerC       |  
    +------------------------+  
    | + handleRequest()      |  
    | + setNextHandler()     |  
    +------------------------+  

3. 责任链模式的实现

通过一个实际的例子来演示责任链模式的实现。假设我们有一个处理请求的系统,每个请求有一个不同的级别(如:低、中、高),我们希望根据请求的级别来选择处理它的处理者。

3.1 Java 示例代码
// 抽象处理者
abstract class Handler {
    protected Handler nextHandler;

    public void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }

    public abstract void handleRequest(int level);
}

// 具体处理者A
class ConcreteHandlerA extends Handler {
    @Override
    public void handleRequest(int level) {
        if (level <= 10) {
            System.out.println("ConcreteHandlerA处理请求,级别:" + level);
        } else if (nextHandler != null) {
            nextHandler.handleRequest(level); // 转发请求
        }
    }
}

// 具体处理者B
class ConcreteHandlerB extends Handler {
    @Override
    public void handleRequest(int level) {
        if (level <= 20) {
            System.out.println("ConcreteHandlerB处理请求,级别:" + level);
        } else if (nextHandler != null) {
            nextHandler.handleRequest(level); // 转发请求
        }
    }
}

// 具体处理者C
class ConcreteHandlerC extends Handler {
    @Override
    public void handleRequest(int level) {
        if (level <= 30) {
            System.out.println("ConcreteHandlerC处理请求,级别:" + level);
        } else if (nextHandler != null) {
            nextHandler.handleRequest(level); // 转发请求
        }
    }
}

// 客户端代码
public class ChainOfResponsibilityPatternDemo {
    public static void main(String[] args) {
        // 创建责任链中的处理者
        Handler handlerA = new ConcreteHandlerA();
        Handler handlerB = new ConcreteHandlerB();
        Handler handlerC = new ConcreteHandlerC();

        // 设置责任链
        handlerA.setNextHandler(handlerB);
        handlerB.setNextHandler(handlerC);

        // 客户端发出请求
        System.out.println("请求级别为10:");
        handlerA.handleRequest(10); // 由A处理

        System.out.println("\n请求级别为15:");
        handlerA.handleRequest(15); // 由B处理

        System.out.println("\n请求级别为25:");
        handlerA.handleRequest(25); // 由C处理

        System.out.println("\n请求级别为35:");
        handlerA.handleRequest(35); // 没有处理者能处理该请求
    }
}

输出结果

请求级别为10:
ConcreteHandlerA处理请求,级别:10

请求级别为15:
ConcreteHandlerB处理请求,级别:15

请求级别为25:
ConcreteHandlerC处理请求,级别:25

请求级别为35:
(无输出)
3.2 解释
  • ConcreteHandlerA 只能处理请求级别小于或等于 10 的请求。如果请求级别大于 10,它会将请求转发给 ConcreteHandlerB 处理。
  • ConcreteHandlerB 只能处理请求级别小于或等于 20 的请求,超过这个级别的请求会被转发给 ConcreteHandlerC
  • ConcreteHandlerC 只能处理请求级别小于或等于 30 的请求。
  • 如果请求级别超过 30,责任链中没有任何处理者可以处理此请求,系统将不会输出任何内容。

4. 责任链模式的应用场景

责任链模式适用于以下场景:

  1. 多个对象可以处理一个请求:当一个请求可以由多个对象中的任何一个对象来处理时,可以使用责任链模式来处理。例如:请求的处理依赖于请求的级别或类型。
  2. 请求处理者的顺序不确定:当请求处理的顺序可以灵活变化时,可以使用责任链模式。例如:日志记录系统中的不同日志级别处理器,日志处理器可以按优先级顺序链式连接。
  3. 请求的处理者不一定知道最终的处理者是谁:责任链模式通过将请求沿链传递,避免了请求发送者和处理者之间的紧耦合。
  4. 动态地为请求分配处理者:通过责任链模式,可以动态地改变请求的处理顺序,甚至添加新的处理者。

5. 责任链模式的优缺点

5.1 优点
  • 降低耦合度:请求的发送者不需要知道哪个具体对象会处理请求,只需要知道责任链的起始处理者即可。这使得发送者和处理者之间的耦合度较低。
  • 增强灵活性:通过改变责任链的顺序,可以灵活地调整请求处理的方式,而无需修改请求的发送者或处理者。
  • 可扩展性强:责任链模式可以轻松地扩展新的处理者,只需将新的处理者添加到链中即可。
5.2 缺点
  • 可能导致请求得不到处理:如果责任链中的每个处理者都不能处理请求,那么请求就会一直在链中传递,直到超出链的范围。此时,客户端就无法获得处理结果。
  • 调试难度较大:由于请求会沿着链传递,可能会导致请求的跟踪变得较为困难,尤其是在责任链很长的情况下。

6. 责任链模式的实际应用

责任链模式广泛应用于实际项目中,特别是在处理一系列操作或任务时,以下是一些常见的应用场景:

  1. 日志处理系统:不同的日志记录器根据日志级别(如 DEBUG、INFO、ERROR)进行处理,日志处理器通常是责任链模式的一个典型应用。
  2. 审批流程:例如在企业的工作流系统中,某些任务可能需要多级审批,责任链模式可以非常自然地实现不同级别的审批处理。
  3. 事件处理系统:在 GUI 事件处理中,事件可以在多个事件监听器之间传递,直到某个监听器处理完该事件为止。
  4. 命令处理系统:例如,HTTP 请求处理中的路由系统,可以将请求传递给不同的处理器,根据请求的类型选择合适的处理逻辑。

7. 总结

责任链模式是一种行为型设计模式,通过将请求沿链传递,直到有一个对象处理它为止。它的主要优点是降低了请求发送者与处理者之间的耦合度,增强了系统的灵活性和可扩展性。然而,责任链模式也存在请求无法得到处理的风险以及调试上的难度。在适当的场景下,责任链模式可以有效地提高系统的设计灵活性和可维护性。

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

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

相关文章

记录日志中logback和log4j2不能共存的问题

本文章记录设置两个日志时候&#xff0c;控制台直接报错 标黄处就是错误原因&#xff1a;1. SLF4J(W)&#xff1a;类路径包含多个SLF4J提供程序。 SLF4J(W)&#xff1a;找到提供程序[org.apache.logging.slf4j. net]。 SLF4J(W)&#xff1a;找到提供程序[ch.qos.log .classi…

丹摩征文活动 |通过Pycharm复现命名实体识别模型--MECT模型

文章目录 &#x1f34b;1 引言&#x1f34b;2 平台优势&#x1f34b;3 丹摩平台服务器配置教程&#x1f34b;4 实操案例&#xff08; MECT4CNER-main&#xff09;&#x1f34b;4.1 MECT4CNER-main模型&#x1f34b;4.2 环境配置&#x1f34b;4.3 训练模型&#x1f34b;4.4 数据…

电脑浏览器打不开网页怎么办 浏览器无法访问网页解决方法

我们在使用电脑的时候&#xff0c;使用浏览器是经常的&#xff0c;很多用户在点开浏览器时&#xff0c;却遇到浏览器无法访问网页的情况。那么电脑浏览器打不开网页是什么原因呢&#xff1f;今天小编就给大家分享几个常见的原因和具体的解决方法&#xff0c;希望能对大家有所帮…

YOLOv11实战宠物狗分类

本文采用YOLOv11作为核心算法框架&#xff0c;结合PyQt5构建用户界面&#xff0c;使用Python3进行开发。YOLOv11以其高效的特征提取能力&#xff0c;在多个图像分类任务中展现出卓越性能。本研究针对5种宠物狗数据集进行训练和优化&#xff0c;该数据集包含丰富的宠物狗图像样本…

Struts源码阅读——三个常用的辅助类DispatchAction

Struts源码阅读——三个常用的辅助类 紧接前文&#xff0c;我们来阅读org.apache.struts.actions包中三个常用类的源码。 DispatchAction、LookupDispatchAction 和 MappingDispatchAction 是 Struts 1 框架中的三个常用的辅助类&#xff0c;用来简化 Action 类中的请求分发。…

Linux设置Nginx开机启动

操作系统环境&#xff1a;CentOS 7 【需要 root 权限&#xff0c;使用 root 用户进行操作】 原理&#xff1a;利用 systemctl 管理服务 设置 Nginx 开机启动 需要 root 权限&#xff0c;普通用户使用 sudo 进行命令操作 原理&#xff1a;利用 systemctl 管理服务 1、新建…

C# WPF 记录DataGrid的表头顺序,下次打开界面时应用到表格中

效果&#xff1a; 代码实现 前端 <DataGrid x:Name"DataGrid1"<!--定义当列位置变化后的触发事件-->CanUserReorderColumns"True"ColumnReordered"DataGrid_ColumnReordered"rubyer:ControlHelper.FocusedForegroundBrush"{Stati…

Transformer-BiLSTM、Transformer、CNN-BiLSTM、BiLSTM、CNN五模型多变量回归预测

Transformer-BiLSTM、Transformer、CNN-BiLSTM、BiLSTM、CNN五模型多变量回归预测 目录 Transformer-BiLSTM、Transformer、CNN-BiLSTM、BiLSTM、CNN五模型多变量回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 吐血售&#xff01;聚划算&#xff01;Transforme…

面试官:如何设计一个能够支持高并发的系统?

强烈推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站:人工智能 设计一个支持高并发的系统是一个系统工程&#xff0c;涉及多个层面的优化。以下逐一展开说明&#xff1a; 1. 分布式架…

企业数字化转型指南:如何通过价值流推动业务创新与变革

在全球企业加速数字化转型的浪潮中&#xff0c;企业领导者和技术人员必须理解数字化转型的核心不只是技术的应用&#xff0c;而是业务流程的彻底重塑。根据《价值流&#xff08;Value Streams&#xff09;》中的理论框架&#xff0c;数字化转型的关键在于价值流&#xff08;Val…

知识库管理系统:企业数字化转型的加速器

在数字化转型的大潮中&#xff0c;知识库管理系统&#xff08;KBMS&#xff09;已成为企业提升效率和创新能力的关键工具。本文将探讨知识库管理系统的定义、企业建立知识库的必要性&#xff0c;以及如何快速搭建企业知识库。 知识库管理系统是什么&#xff1f; 知识库管理系统…

Python 绘图工具详解:使用 Matplotlib、Seaborn 和 Pyecharts 绘制散点图

目录 数据可视化1.使用 matplotlib 库matplotlib 库 2 .使用 seaborn 库seaborn 库 3 .使用 pyecharts库pyecharts库 注意1. 确保安装了所有必要的库2. 检查Jupyter Notebook的版本3. 使用render()方法保存为HTML文件4. 使用IFrame在Notebook中显示HTML文件5. 检查是否有其他输…

JAVA学习日记(十五) 数据结构

一、数据结构概述 数据结构是计算机底层存储、组织数据的方式。 数据结构是指数据相互之间以什么方式排列在一起的。 数据结构是为了更加方便的管理和使用数据&#xff0c;需要结合具体的业务场景来进行选择。 二、常见的数据结构 &#xff08;一&#xff09;栈 特点&…

【C++】—掌握STL vector 类:“Vector简介:动态数组的高效应用”

文章目录 1.vector的介绍和使用1.1vector的介绍1.2 vector的特点1.3vector的使用1.3.1vector的定义1.3.2vector iterator的使用1.3.3vector 的空间增长问题1.3.4 vector 的增删查改1.3.5vector 迭代器失效问题 1.vector的介绍和使用 1.1vector的介绍 vector是一个顺序容器&am…

PTE-中间件安全

DOCKER环境&#xff0c;一般是80 8080 8081端口 1 apache位置扩展名解析漏洞 cd vulhub-master/httpd/apache_parsing_vulnerability/ docker-compose up -d 修改一句话的后缀 直接上传 蚁剑 2 CVE-2017-15715 docker-compose stop cd .. cd CVE-2017-15715/ dock…

Python用CEEMDAN-LSTM-VMD金融股价数据预测及SVR、AR、HAR对比可视化

全文链接&#xff1a;https://tecdat.cn/?p38224 分析师&#xff1a;Duqiao Han 股票市场是一个复杂的非线性系统&#xff0c;股价受到许多经济和社会因素的影响。因此&#xff0c;传统的线性或近线性预测模型很难有效、准确地预测股票指数的价格趋势。众所周知&#xff0c;深…

【Revit二次开发】创建Ribbon选项卡与带图标的按钮

效果图 创建一个叫做“开发的插件”的选项卡&#xff0c; 选项卡内有一个叫做“Hello”的图标按钮&#xff0c; 点击按钮后运行一个命令&#xff0c; 该命令弹出提示框“Hello Revit!”。 在此示例基础上&#xff0c;可以根据需要替换图标、文字、命令功能。 步骤 安装Revit…

Java面试要点18 - Java运行时多态与编译时多态

本文目录 一、引言二、运行时多态的实现三、编译时多态的实现四、多态与接口五、多态的实际应用六、总结 一、引言 多态是面向对象编程的三大特性之一&#xff0c;它允许我们以统一的方式处理不同类型的对象。Java中的多态分为两种&#xff1a;编译时多态&#xff08;重载&…

使用@react-three/fiber,@mkkellogg/gaussian-splats-3d加载.splat,.ply,.ksplat文件

前言 假设您正在现有项目中集成这些包&#xff0c;而该项目的构建工具为 Webpack 或 Vite。同时&#xff0c;您对 Three.js 和 React 有一定的了解。如果您发现有任何错误或有更好的方法&#xff0c;请随时留言。 安装 npm install three types/three react-three/fiber rea…

HBase理论_背景特点及数据单元及与Hive对比

本文结合了个人的笔记以及工作中实践经验以及参考HBase官网&#xff0c;我尽可能把自己的知识点呈现出来&#xff0c;如果有误&#xff0c;还请指正。 1. HBase背景 HBase作为面向列的数据库运行在HDFS之上&#xff0c;HDFS缺乏随机读写操作&#xff0c;HBase正是为此而出现。…