【设计模式精讲 Day 13】责任链模式(Chain of Responsibility Pattern)


文章内容

在“设计模式精讲”系列的第13天,我们将深入讲解责任链模式(Chain of Responsibility Pattern)。这是一种行为型设计模式,它通过将请求的发送者和接收者解耦,使得多个对象都有机会处理请求,从而避免了请求的发送者与接收者之间的紧耦合。

责任链模式的核心思想是:将请求的处理过程组织成一个链式结构,每个处理节点可以决定是否处理该请求或将其传递给下一个节点。这种模式非常适合处理需要多个条件判断、权限校验、审批流程等场景,能够有效提升系统的灵活性和可扩展性。

本篇文章将从理论到实践全面解析责任链模式,包括其定义、结构、适用场景、实现方式、工作原理、优缺点分析,并结合真实项目案例进行深入探讨。同时,我们还将展示如何在Java中实现责任链模式,并讨论其在Java标准库及主流框架中的应用实例。


模式定义

责任链模式(Chain of Responsibility Pattern) 是一种行为型设计模式,它允许你将请求的发送者与接收者解耦。请求通过一系列处理对象进行传递,直到某个对象决定处理它为止。每个处理对象都包含对下一个处理对象的引用,形成一条链。

该模式的核心思想是:

  • 解耦请求的发送者与接收者
  • 允许多个对象有机会处理请求
  • 动态构建处理链

模式结构

责任链模式由以下几个关键角色组成:

角色说明
抽象处理者(Handler)定义处理请求的接口,通常包含一个指向下一个处理者的引用。
具体处理者(Concrete Handler)实现具体的处理逻辑,决定是否处理请求或将其传递给下一个处理者。
客户端(Client)创建处理链并发起请求。

类图结构描述

+----------------+
|   Handler      |
+----------------+
| - next: Handler|
+----------------+
| + setNext()    |
| + handleRequest()|
+----------------+▲│
+----------------+
| ConcreteHandlerA|
+----------------+
| + handleRequest()|
+----------------+▲│
+----------------+
| ConcreteHandlerB|
+----------------+
| + handleRequest()|
+----------------+

每个具体处理者继承自抽象处理者,维护一个对下一个处理者的引用。当当前处理者无法处理请求时,它会将请求传递给下一个处理者。


适用场景

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

场景说明
多级审批流程如请假审批、报销申请、合同签署等,不同层级的审批人按顺序处理请求
权限验证在系统中对用户权限进行逐级验证,如登录、访问控制、操作权限等
日志记录不同级别的日志信息被不同处理器处理,如调试日志、错误日志、审计日志
过滤器链Web开发中的过滤器(Filter)、拦截器(Interceptor)等
事件处理GUI事件、消息队列中的消息处理等

这些场景中,请求的处理可能涉及多个步骤,且处理逻辑具有一定的优先级或顺序性,此时使用责任链模式能有效提高系统的可维护性和可扩展性。


实现方式

下面是一个完整的 Java 示例,演示责任链模式的基本实现。

抽象处理者(Handler)
// 抽象处理者
public abstract class Handler {protected Handler next;public void setNext(Handler next) {this.next = next;}// 处理请求的方法public void handleRequest(Request request) {if (canHandle(request)) {doHandle(request);} else if (next != null) {next.handleRequest(request);} else {System.out.println("No handler can process the request.");}}// 判断是否可以处理该请求protected abstract boolean canHandle(Request request);// 具体处理逻辑protected abstract void doHandle(Request request);
}
具体处理者(Concrete Handler)
// 具体处理者1:处理普通请求
public class ConcreteHandlerA extends Handler {@Overrideprotected boolean canHandle(Request request) {return request.getType() == RequestType.NORMAL;}@Overrideprotected void doHandle(Request request) {System.out.println("ConcreteHandlerA handled the request: " + request.getMessage());}
}// 具体处理者2:处理紧急请求
public class ConcreteHandlerB extends Handler {@Overrideprotected boolean canHandle(Request request) {return request.getType() == RequestType.EMERGENCY;}@Overrideprotected void doHandle(Request request) {System.out.println("ConcreteHandlerB handled the request: " + request.getMessage());}
}
请求类(Request)
// 请求类
public class Request {private RequestType type;private String message;public Request(RequestType type, String message) {this.type = type;this.message = message;}public RequestType getType() {return type;}public String getMessage() {return message;}
}
枚举类型(RequestType)
// 请求类型枚举
public enum RequestType {NORMAL,EMERGENCY
}
客户端调用示例
public class Client {public static void main(String[] args) {// 创建处理链Handler handlerA = new ConcreteHandlerA();Handler handlerB = new ConcreteHandlerB();handlerA.setNext(handlerB);// 发起请求Request request1 = new Request(RequestType.NORMAL, "This is a normal request.");Request request2 = new Request(RequestType.EMERGENCY, "This is an emergency request.");handlerA.handleRequest(request1); // 会被ConcreteHandlerA处理handlerA.handleRequest(request2); // 会被ConcreteHandlerB处理}
}
单元测试代码(JUnit 5)
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;public class ChainOfResponsibilityTest {@Testpublic void testChainOfResponsibility() {Handler handlerA = new ConcreteHandlerA();Handler handlerB = new ConcreteHandlerB();handlerA.setNext(handlerB);Request request1 = new Request(RequestType.NORMAL, "Normal request");Request request2 = new Request(RequestType.EMERGENCY, "Emergency request");handlerA.handleRequest(request1);handlerA.handleRequest(request2);}
}

工作原理

责任链模式通过链式结构来传递请求,每个处理者都拥有对下一个处理者的引用。当请求到达链头时,第一个处理者尝试处理,如果不能处理,则将请求传递给下一个处理者,依此类推。

这种方式的优点在于:

  • 请求的发送者不需要知道具体由哪个处理者处理,只需将请求发送到链头即可。
  • 处理链可以动态构建和修改,无需修改请求发送者的代码。
  • 提高了系统的可扩展性,新增处理者只需加入链中,不影响现有逻辑。

优缺点分析

优点缺点
解耦请求的发送者与接收者链式结构可能导致调试困难
提高系统的灵活性和可扩展性请求可能未被任何处理者处理,需注意边界情况
支持动态配置处理链若链过长,可能影响性能
易于添加新的处理者需要合理设计处理顺序,否则可能造成逻辑混乱

案例分析:企业审批系统

假设我们正在开发一个企业内部的审批系统,用于处理员工的请假申请。根据请假天数的不同,审批流程也不同:

  • 1天以内:部门经理审批
  • 2~5天:部门经理 + 人事部审批
  • 5天以上:部门经理 + 人事部 + 总经理审批

在这种情况下,使用责任链模式可以很好地组织审批流程,而无需在请求发送者中硬编码审批路径。

代码实现
// 抽象处理者
public abstract class ApprovalHandler {protected ApprovalHandler next;public void setNext(ApprovalHandler next) {this.next = next;}public void approve(LeaveRequest request) {if (canApprove(request)) {doApprove(request);} else if (next != null) {next.approve(request);} else {System.out.println("No approver can process the request.");}}protected abstract boolean canApprove(LeaveRequest request);protected abstract void doApprove(LeaveRequest request);
}// 具体处理者:部门经理
public class ManagerApprover extends ApprovalHandler {@Overrideprotected boolean canApprove(LeaveRequest request) {return request.getDays() <= 1;}@Overrideprotected void doApprove(LeaveRequest request) {System.out.println("Manager approved: " + request.getEmployeeName() + " for " + request.getDays() + " days.");}
}// 具体处理者:人事部
public class HRApprover extends ApprovalHandler {@Overrideprotected boolean canApprove(LeaveRequest request) {return request.getDays() > 1 && request.getDays() <= 5;}@Overrideprotected void doApprove(LeaveRequest request) {System.out.println("HR approved: " + request.getEmployeeName() + " for " + request.getDays() + " days.");}
}// 具体处理者:总经理
public class CEOApprover extends ApprovalHandler {@Overrideprotected boolean canApprove(LeaveRequest request) {return request.getDays() > 5;}@Overrideprotected void doApprove(LeaveRequest request) {System.out.println("CEO approved: " + request.getEmployeeName() + " for " + request.getDays() + " days.");}
}// 请求类
public class LeaveRequest {private String employeeName;private int days;public LeaveRequest(String employeeName, int days) {this.employeeName = employeeName;this.days = days;}public String getEmployeeName() {return employeeName;}public int getDays() {return days;}
}// 客户端
public class LeaveApprovalSystem {public static void main(String[] args) {ApprovalHandler manager = new ManagerApprover();ApprovalHandler hr = new HRApprover();ApprovalHandler ceo = new CEOApprover();manager.setNext(hr);hr.setNext(ceo);LeaveRequest request1 = new LeaveRequest("Alice", 1);LeaveRequest request2 = new LeaveRequest("Bob", 3);LeaveRequest request3 = new LeaveRequest("Charlie", 7);manager.approve(request1); // 被部门经理处理manager.approve(request2); // 被人事部处理manager.approve(request3); // 被总经理处理}
}

在这个案例中,责任链模式清晰地表达了审批流程的层次结构,使系统更易于维护和扩展。例如,若以后需要增加新的审批级别,只需添加一个新的处理者并将其链接到链中即可。


与其他模式的关系

责任链模式常常与其他设计模式结合使用,以增强其功能或解决更复杂的问题:

模式关系说明
命令模式(Command Pattern)命令模式封装请求为对象,责任链模式则处理请求链,二者可以结合使用,实现灵活的请求处理机制
观察者模式(Observer Pattern)责任链模式关注请求的传递,而观察者模式关注事件的通知,二者可以协同工作,实现事件驱动的系统
策略模式(Strategy Pattern)责任链模式强调处理链的顺序,而策略模式强调算法的替换,两者可以配合使用,实现不同的处理策略
装饰器模式(Decorator Pattern)责任链模式和装饰器模式都采用组合方式扩展对象功能,但责任链模式更关注请求的处理流程,而装饰器模式更关注对象的行为增强

总结

今天我们学习了责任链模式的核心思想、结构、适用场景、实现方式、工作原理、优缺点分析,并通过实际项目案例进行了深入讲解。责任链模式通过解耦请求的发送者与接收者,使得多个对象有机会处理请求,提升了系统的灵活性和可扩展性。

在Java中,责任链模式可以通过抽象类和链式引用实现,适用于审批流程、权限验证、日志处理等多种场景。此外,责任链模式还可以与其他设计模式(如命令模式、观察者模式)结合使用,进一步增强系统的功能和可维护性。

下一天我们将进入“设计模式精讲”的第14天,讲解命令模式(Command Pattern),敬请期待!


文章标签

design-patterns, java, software-architecture, oop, chain-of-responsibility


文章简述

本文详细介绍了设计模式中的责任链模式(Chain of Responsibility Pattern),通过理论与实践结合的方式,帮助Java开发工程师理解其核心思想、实现方式以及应用场景。文章提供了完整的Java代码示例,展示了如何构建责任链结构,并通过企业审批系统的真实案例说明其实际价值。责任链模式通过解耦请求的发送者与接收者,提高了系统的灵活性和可扩展性,特别适合多级审批、权限验证、日志处理等场景。本文不仅涵盖了模式的基本概念,还深入分析了其与其它设计模式的关系,并提供了单元测试代码,确保读者能够直接应用到实际项目中。


进一步学习资料

  1. Design Patterns: Elements of Reusable Object-Oriented Software
  2. Refactoring Guru - Chain of Responsibility
  3. Java Design Patterns - Chain of Responsibility
  4. Martin Fowler’s Patterns of Enterprise Application Architecture
  5. Head First Design Patterns

核心设计思想总结

  • 责任链模式通过链式结构传递请求,实现解耦与灵活处理
  • 适用于多级审批、权限验证、日志处理等场景
  • 在Java中可通过抽象类和链式引用实现
  • 应避免链过长导致性能问题,注意边界条件处理
  • 可与其他设计模式(如命令模式、观察者模式)结合使用

希望本文能帮助你在实际项目中更好地理解和应用责任链模式,提升系统的设计质量与可维护性。

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

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

相关文章

h-ui面板 hysteria2

搭建文档 项目地址&#xff1a;https://github.com/jonssonyan/h-ui/blob/main/README_ZH.md参考视频&#xff1a;https://www.youtube.com/watch?vNi3iaLOsH_A一键部署命令 # root权限 sudo -ibash <(curl -fsSL https://raw.githubusercontent.com/jonssonyan/h-ui/mai…

自动登录脚本神器-Mac电脑实现自动登录堡垒机并自动输入账号密码跳转不同机器环境

先讲下背景&#xff1a; 公司电脑需要先登录堡垒机&#xff0c;然后再从堡垒机跳转到具体生产机器&#xff0c;每次输入堡垒机都要通过Authenticator里的2FC的码做验证&#xff0c;然后再跳到堡垒机还要再输入一次账号密码&#xff0c;为了方便快速登录机器&#xff0c;可以制…

【C/C++】C++26新特性前瞻:全面解析未来编程

展望未来&#xff1a;C26 新特性全面解析 随着 C 标准每三年一次的迭代节奏&#xff0c;C26&#xff08;预计于 2026 年底正式发布&#xff09;正在逐步成型。相比 C20 的革命性更新和 C23 的“修补增强”&#xff0c;C26 继续推进现代 C 的理念——更安全、更高效、更模块化&…

ArXiv 2101 | Rethinking Interactive Image Segmentation Feature Space Annotation

Rethinking Interactive Image Segmentation Feature Space Annotation Author: lartpangLink: https://github.com/lartpang/blog/issues/10论文&#xff1a;https://arxiv.org/abs/2101.04378代码&#xff1a;https://github.com/LIDS-UNICAMP/rethinking-interactive-image…

架构经验总结

20250511-总结经验 一、SOA 1&#xff09;过程&#xff1a;需求分析、系统设计、系统实现、构件组装、部署运维、后开发阶段。 2&#xff09;特点&#xff1a;无状态、单一职责、明确定义接口、自包含、模块化、粗粒度、重用性、兼容性、互操作性、松耦合、策略声明。 3&…

debain切换 opensuse 我都安装了什么

绿色进度条后&#xff0c;黑屏&#xff08;只有一个下划线&#xff09;等待 使用 nomodeset 属性解决 进入系统无法连接 wifi&#xff0c;只能使用网线连接 wifi 这个我在安装中文字体后&#xff0c;注销登录&#xff0c;得到了解决&#xff0c;不确定是不是字体问题。&#x…

思科ISE/ISE-PIC安全警报:两处高危RCE漏洞(CVSS 10.0)可致未授权获取root权限

思科已发布更新&#xff0c;修复身份服务引擎&#xff08;Identity Services Engine&#xff0c;ISE&#xff09;及ISE被动身份连接器&#xff08;ISE-PIC&#xff09;中两处最高危安全漏洞&#xff0c;这些漏洞可能允许未经认证的攻击者以root用户身份执行任意命令。 漏洞详情…

智能助手(利用GPT搭建智能系统)

项目介绍 本项目旨在打造一个基于通义千问模型的智能助手&#xff0c;能够理解用户指令并自动生成可执行的 JavaScript 代码。该代码可直接调用预设接口&#xff0c;完成指定操作&#xff0c;并返回执行结果。通过大模型的理解与生成能力&#xff0c;实现从自然语言到接口调用…

【源码+文档+调试讲解】基于web的运动健康小程序的设计与实现y196

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对高校教师成果信息管理混乱&#xff0c;出错率高&#xff0c;信息安全…

临床项目计划框架

一、项目概述 1.1 项目名称 项目名称:评估XX药物在YY患者中安全性和有效性的III期随机对照试验 1.2 项目背景与立项依据 1.2.1 研究背景 简述疾病负担、当前治疗现状、未满足的医疗需求,为项目开展提供背景支持。 1.2.2 科学依据 总结前期研究结果、理论基础、研究假设的形…

Hoare逻辑与分离逻辑:从程序验证到内存推理的演进

文章目录 引言一、Hoare逻辑基础&#xff1a;程序正确性的形式化验证&#x1f330; 例子&#xff1a;简单赋值语句的Hoare逻辑验证&#x1f330; 例子&#xff1a;条件语句的Hoare逻辑验证 二、分离逻辑&#xff1a;Hoare逻辑在内存管理中的扩展&#x1f50d; 分离逻辑的核心扩…

Tomcat Maven 插件

在 Maven 项目中&#xff0c;可以使用 Tomcat Maven 插件&#xff08;tomcat7-maven-plugin 或 tomcat-maven-plugin&#xff09;来直接部署 WAR 文件到 Tomcat 服务器&#xff0c;而无需手动复制 WAR 文件到 webapps 目录。以下是详细的使用方法&#xff1a; 1. 配置 Tomcat M…

【开源工具】一键解决使用代理后无法访问浏览器网页问题 - 基于PyQt5的智能代理开关工具开发全攻略

&#x1f310;【开源工具】一键解决使用代理后无法访问浏览器网页问题 - 基于PyQt5的智能代理开关工具开发全攻略 &#x1f308; 个人主页&#xff1a;创客白泽 - CSDN博客 &#x1f525; 系列专栏&#xff1a;&#x1f40d;《Python开源项目实战》 &#x1f4a1; 热爱不止于代…

异步IO框架io_uring实现TCP服务器

一、io_uring介绍 io_uring是 Linux 于 2019 年加入到内核的一种新型异步 I/O 模型&#xff0c;io_uring 主要为了解决 原生AIO&#xff08;Native AIO&#xff09; 存在的一些不足之处。下面介绍一下原生 AIO 的不足之处&#xff1a; 系统调用开销大&#xff1a;提交 I/O 操作…

【docker】docker run参数说明

功能 拉起容器。 参数 -i&#xff0c;--interactive 保持容器标准输入放开&#xff0c;就算没有终端也放开。 可以理解为可以向容器内输入东西&#xff0c;比如&#xff1a; [rootlocalhost ~]# echo 111 | docker run -i yaxin:1.0 cat 111--cap-add 用于向容器添加特定的…

从0开始学习计算机视觉--Day04--损失函数

在上次学习中&#xff0c;我们知道了线性分类的函数是f(x,W),但并没有解释要怎么得到W权重矩阵的值&#xff0c;以及我们要怎么用训练数据来确定它的最优权重矩阵。在之前我们知道&#xff0c;假设用了10种类别的图片用于训练&#xff0c;将其中一种图片输入模型后&#xff0c;…

【V2.0】TPS-61088升压板-3.7V升压到9V电源板

优化一下上一版本的升压板&#xff1a; TPS-61088升压板-3.7V升压到9V电源板-CSDN博客 改动参考了官方的demo板 加了很多的电容&#xff0c;封装很大&#xff0c;同时去掉了AGND&#xff0c;直接使用一个GND。 补偿电路增加了一个47pF的电容。 EN引脚改用输入的电压分压来启…

基于DeepSeek搭建Dify智能助手国产化架构运行arm64

基于DeepSeek搭建Dify智能助手国产化架构运行arm64 基于DeepSeek搭建Dify智能助手案例介绍案例内容1 概述1.1 背景介绍1.2 适用对象1.3 案例时间1.4 案例流程1.5 资源总览 2.启动 Docker 容器没有的安装2.1没有Docker安装 3 云主机部署DeepSeek3.1 安装Ollama 4.安装Dify4.1Doc…

PyQtNode Editor 第一篇环境配置

PyQtNode Editor 以其独特的功能和灵活的扩展性&#xff0c;吸引了众多开发者的目光。 这篇博客作为系列开篇&#xff0c;将详细介绍开发 PyQtNode Editor 所需的基础环境、安装步骤&#xff0c;同时深入解读一段简单的 PyQt5 代码&#xff0c;为后续的开发工作奠定基础。 一…

Unity 脚本自动添加头部注释

&#x1f4dd; Unity Script Header 注释生成器 一个轻量、可配置的 Unity 编辑器工具&#xff0c;在创建 .cs 脚本时自动插入统一格式的注释头信息。 支持作者、邮箱、公司、地点、版权、描述等字段&#xff0c;所有信息都可通过 Project Settings 界面配置并动态开关。 &…