当前位置: 首页 > news >正文

【设计模式】职责链模式(责任链模式) 行为型模式,纯与不纯的职责链模式

行为型模式

行为型模式(Behavioral Pattern) 关注系统中对象之间的交互,研究系统在运行时对象之间的相互通信与协作,进一步明确对象的职责

行为型模式:不仅仅关注类和对象本身,还重点关注它们之间的相互作用和职责划分

  • 类行为型模式
    使用继承关系在几个类之间分配行为,主要通过多态等方式来分配父类与子类的职责
  • 对象行为型模式
    使用对象的关联关系来分配行为,主要通过对象关联等方式来分配两个或多个类的职责

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


一、职责链模式简介

职责链模式(Chain of Responsibility Pattern) 是一种 行为型设计模式(对象行为型模式),它允许多个对象有机会处理请求,从而避免请求的发送者和接收者之间的耦合。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

又称为责任链模式

将请求的处理者组织成一条链,并让请求沿着链传递,由链上的处理者对请求进行相应的处理。

客户端无须关心请求的处理细节以及请求的传递,只需将请求发送到链上,将请求的发送者和请求的处理者解耦。

简单来说:

“一个请求可以在多个处理器之间传递,直到找到能够处理该请求的处理器。”

奖学金审批示意图
在这里插入图片描述

分析
辅导员、系主任、院长、校长都可以处理奖学金申请表,他们构成一个处理申请表的链式结构,申请表沿着这条链进行传递,这条链就称为职责链。
职责链可以是一条直线、一个环或者一个树形结构,最常见的职责链是直线型,即沿着一条单向的链来传递请求。

职责链模式包含以下两个角色
Handler(抽象处理者)
ConcreteHandler(具体处理者)

在这里插入图片描述


二、解决的问题类型

职责链模式主要用于解决以下问题:

  • 请求发送者与接收者解耦:发送者不需要知道哪个对象会处理这个请求。在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
  • 动态地分配职责:可以根据需要在运行时调整处理顺序或添加/移除处理器。
  • 支持多种不同的处理方式:可以有多个处理器尝试处理同一个请求。

三、使用场景

  1. 事件流处理:如 GUI 事件处理系统中,不同类型的鼠标点击可能由不同的组件处理。
  2. 权限验证:在 Web 应用中,检查用户是否有权限执行某个操作,可以通过一系列的过滤器来实现。
  3. 日志记录:根据日志级别选择不同的处理器进行日志输出。
  4. 命令解析:命令行工具中,不同的命令可能由不同的处理器负责解析和执行。

四、实际代码案例

假设我们正在开发一个简单的请假审批系统,有不同的角色(经理、主管、HR)可以批准不同天数的请假申请。我们将通过职责链模式来实现这一功能。

1. 定义抽象处理器类

abstract class Approver {protected Approver nextApprover;public void setNextApprover(Approver nextApprover) {this.nextApprover = nextApprover;}public abstract void processRequest(LeaveRequest request);
}

2. 实现具体处理器

class Manager extends Approver {@Overridepublic void processRequest(LeaveRequest request) {if (request.getDays() <= 5) {System.out.println("Manager approved the leave for " + request.getName() + " for " + request.getDays() + " days.");} else if (nextApprover != null) {nextApprover.processRequest(request);}}
}class Director extends Approver {@Overridepublic void processRequest(LeaveRequest request) {if (request.getDays() > 5 && request.getDays() <= 10) {System.out.println("Director approved the leave for " + request.getName() + " for " + request.getDays() + " days.");} else if (nextApprover != null) {nextApprover.processRequest(request);}}
}class HR extends Approver {@Overridepublic void processRequest(LeaveRequest request) {if (request.getDays() > 10) {System.out.println("HR approved the leave for " + request.getName() +" for " + request.getDays() + " days.");} else if (nextApprover != null) {nextApprover.processRequest(request);}}
}

你还可以为最后一个节点添加一个默认行为,比如抛出异常或记录日志:

class DefaultHandler extends Approver {@Overridepublic void processRequest(LeaveRequest request) {System.out.println("No one can approve leave for " + request.getName() +" for " + request.getDays() + " days.");}
}

然后在构建责任链时设置它作为最终节点:

manager.setNextApprover(director);
director.setNextApprover(hr);
hr.setNextApprover(new DefaultHandler());

典型代码(C++)

典型的抽象处理者代码

abstract class Handler
{//维持对下家的引用protected Handler successor;public void SetSuccessor(Handler successor){this.successor = successor;}public abstract void HandleRequest(string request);
}

典型的具体处理者代码

class ConcreteHandler : Handler 
{public override void HandleRequest(string request){if (请求满足条件) {//处理请求}else{this.successor.HandleRequest(request);  //转发请求}}
}

典型的客户端代码

……
Handler handler1, handler2, handler3;
handler1 = new ConcreteHandlerA();
handler2 = new ConcreteHandlerB();
handler3 = new ConcreteHandlerC();
//创建职责链
handler1.SetSuccessor(handler2);
handler2.SetSuccessor(handler3);
//发送请求,请求对象通常为自定义类型
handler1.HandleRequest("请求对象");
……
其他案例
  1. 某企业的SCM(Supply Chain Management,供应链管理)系统中包含一个采购审批子系统。该企业的采购审批是分级进行的,即根据采购金额的不同由不同层次的主管人员来审批,主任可以审批5万元以下(不包括5万元)的采购单,副董事长可以审批5万元至10万元(不包括10万元)的采购单,董事长可以审批10万元至50万元(不包括50万元)的采购单,50万元及以上的采购单就需要开董事会讨论决定。如下图所示:.在这里插入图片描述
    现使用职责链模式设计并实现该系统

在这里插入图片描述

  1. 审批假条
    某OA系统需要提供一个假条审批的模块,如果员工请假天数小于3天,主任可以审批该假条;如果员工请假天数大于等于3天,小于10天,经理可以审批;如果员工请假天数大于等于10天,小于30天,总经理可以审批;如果超过30天,总经理也不能审批,提示相应的拒绝信息。

在这里插入图片描述

3. 定义请求类

为了使例子完整,我们需要定义一个LeaveRequest类来表示请假请求。

class LeaveRequest {private String name;private int days;public LeaveRequest(String name, int days) {this.name = name;this.days = days;}public String getName() {return name;}public int getDays() {return days;}
}

4. 测试代码

接下来,我们可以创建一个测试类来设置责任链并发起请求。

public class Test {public static void main(String[] args) {// 创建责任链上的各个审批者Approver manager = new Manager();Approver director = new Director();Approver hr = new HR();// 设置责任链顺序manager.setNextApprover(director);director.setNextApprover(hr);// 创建请假请求并提交给责任链LeaveRequest request1 = new LeaveRequest("Alice", 3);manager.processRequest(request1);  // 预期: 经理审批LeaveRequest request2 = new LeaveRequest("Bob", 7);manager.processRequest(request2);  // 预期: 主管审批LeaveRequest request3 = new LeaveRequest("Charlie", 12);manager.processRequest(request3);  // 预期: HR审批}
}

五、优缺点分析

优点描述
降低耦合度请求发送者无需知道具体的处理者是谁,只需知道如何传递请求即可。 可简化对象之间的相互连接
增强灵活性可以动态地改变链中的节点顺序或增加新的处理器。
简化对象职责每个处理器只关注自己能处理的部分,符合单一职责原则。
其他增加一个新的具体请求处理者时无须修改原有系统的代码,只需要在客户端重新建链即可
缺点描述
调试困难如果没有处理器处理请求,则很难追踪到问题所在。如果建链不当,可能会造成循环调用,将导致系统陷入死循环
性能开销在长链条上查找合适的处理器可能会导致性能损耗。
可能无法保证请求得到处理若未正确配置责任链,某些请求可能得不到处理。

六、与其他模式对比(补充)

模式名称目标
观察者模式当状态发生变化时通知所有依赖的对象。
策略模式定义一系列算法,并将每个算法封装起来,使它们可以互换。
职责链模式将请求沿责任链传递,直到找到合适的处理器。

七、最终小结

职责链模式是一种非常灵活的设计模式,特别适用于那些需要处理一系列相似请求的场合,且希望保持请求发送者与接收者的解耦。它允许你轻松地扩展处理逻辑而不影响现有的代码结构。


📌 一句话总结:

职责链模式就像一条生产线上的工人,每个工人都负责特定的任务,如果当前工人不能完成任务,他会把任务传给下一个工人,直到任务完成。


推荐使用场景:

  • 当你需要在不修改现有代码的情况下添加新的处理逻辑时。
  • 当处理流程可能因环境变化而需要动态调整时。

八、扩展

纯的职责链模式

一个具体处理者对象只能在两个行为中选择一个:要么承担全部责任,要么将责任推给下家。
不允许出现某一个具体处理者对象在承担了一部分或全部责任后又将责任向下传递的情况。
一个请求必须被某一个处理者对象所接收,不能出现某个请求未被任何一个处理者对象处理的情况。

不纯的职责链模式

允许某个请求被一个具体处理者部分处理后向下传递,或者一个具体处理者处理完某请求后其后继处理者可以继续处理该请求。
一个请求可以最终不被任何处理者对象所接收并处理。

部分内容由AI生成,请注意识别

http://www.dtcms.com/a/276949.html

相关文章:

  • 前端框架状态管理对比:Redux、MobX、Vuex 等的优劣与选择
  • ALB、NLB、CLB 负载均衡深度剖析
  • 闲庭信步使用图像验证平台加速FPGA的开发:第十二课——图像增强的FPGA实现
  • axios拦截器
  • spring cloud负载均衡分析之FeignBlockingLoadBalancerClient、BlockingLoadBalancerClient
  • 【Qt开发】Qt的背景介绍(一)
  • 时序预测 | Matlab代码实现VMD-TCN-GRU-MATT变分模态分解时间卷积门控循环单元多头注意力多变量时序预测
  • [特殊字符] Python自动化办公 | 3步实现Excel数据清洗与可视化,效率提升300%
  • 开源链动2+1模式、AI智能名片与S2B2C商城小程序在私域运营中的协同创新研究
  • 从零开始跑通3DGS教程:(五)3DGS训练
  • 《区间dp》
  • 一文读懂现代卷积神经网络—深度卷积神经网络(AlexNet)
  • 深入理解观察者模式:构建松耦合的交互系统
  • Redis技术笔记-从三大缓存问题到高可用集群落地实战
  • ESP-Timer入门(基于ESP-IDF-5.4)
  • JVM:内存、类加载与垃圾回收
  • 每天一个前端小知识 Day 30 - 前端文件处理与浏览器存储机制实践
  • [Rust 基础课程]选一个合适的 Rust 编辑器
  • 通用定时器GPT
  • 输入npm install后发生了什么
  • # 通过wifi共享打印机只有手动翻页正反打印没有自动翻页正反打印,而通过网线连接的主机电脑可以自动翻页正反打印
  • OneCode3.0 VFS分布式文件管理API速查手册
  • Codeforces Round 855 (Div. 3)
  • 【iOS】方法与消息底层分析
  • 动物世界一语乾坤韵芳华 人工智能应用大学毕业论文 -仙界AI——仙盟创梦IDE
  • Docker Compose文件内容解释
  • 鸿蒙选择本地视频文件,并获取首帧预览图
  • 14.ResourceMangaer启动解析
  • 【java】AI内容用SSE流式输出
  • 【读书笔记】《C++ Software Design》第七章:Bridge、Prototype 与 External Polymorphism