设计模式学习(25) 23-23 责任链模式

文章目录

  • [0. 个人感悟](#0. 个人感悟)
  • [1. 概念](#1. 概念)
  • [2. 适配场景](#2. 适配场景)
    • [2.1 适合的场景](#2.1 适合的场景)
    • [2.2 常见场景举例](#2.2 常见场景举例)
  • [3. 实现方法](#3. 实现方法)
    • [3.1 实现思路](#3.1 实现思路)
    • [3.2 UML类图](#3.2 UML类图)
    • [3.3 代码示例](#3.3 代码示例)
  • [4. 优缺点](#4. 优缺点)
    • [4.1 优点](#4.1 优点)
    • [4.2 缺点](#4.2 缺点)
  • [5. 源码分析](#5. 源码分析)

0. 个人感悟

  • 责任链模式如其名,让接受者都有机会处理消息,链式调用
  • 传统方式按流程来累代码,处理消息的代码会有很多的if-else判断由谁来处理,这样不仅职责不单一,而且需要了解处理者的实现逻辑,耦合太重;责任链模式可以让消息发送者和处理者解耦,发送者不需要知道谁来处理,各个处理者只需要做好自己的业务和消息传递就好
  • 类似于现实中"踢皮球"或"层层审批"的流程
  • 可以和模版方法模式配合,抽象一个基础handler,后面代码里有示例,有兴趣可以看看

1. 概念

英文定义 (《设计模式:可复用面向对象软件的基础》)

Avoid coupling the sender of request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.

中文翻译

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

理解

  • 解耦请求发送者和接收者,发送者不需要知道谁来处理请求
  • 多个处理器对象组成一条链,请求沿着链传递
  • 每个处理器决定是否处理请求,以及是否传递给下一个处理器
  • 核心是处理器的"链式"组织和请求的"传递"机制

2. 适配场景

2.1 适合的场景

  • 多级审批系统:请假、报销、采购等需要多级审批的业务流程
  • 过滤器和拦截器:Web框架中的过滤器链、拦截器链
  • 事件处理:GUI中的事件传递,如按钮点击事件冒泡
  • 异常处理:不同级别的异常由不同的处理器处理
  • 日志记录:不同级别的日志信息由不同的处理器记录
  • 责任分离:将复杂的处理逻辑分解为多个小处理器
  • 动态可配置的处理流程:处理流程可以运行时动态调整

2.2 常见场景举例

  1. 请假审批系统:员工提交请假申请 → 组长审批 → 经理审批 → HR备案
  2. Web请求处理:请求 → 字符编码过滤器 → 安全过滤器 → 日志过滤器 → 业务处理
  3. Java异常处理:try-catch-finally,异常沿着调用栈向上传递
  4. 日志系统:DEBUG → INFO → WARN → ERROR,不同级别的日志由不同处理器处理
  5. 游戏事件处理:鼠标点击事件 → UI系统 → 游戏对象系统 → 物理引擎

3. 实现方法

3.1 实现思路

  1. 定义抽象处理器接口/抽象类

    • 声明处理请求的方法
    • 定义设置后继处理器的方法
    • 可选:定义处理请求的模板方法
  2. 实现具体处理器类

    • 实现处理逻辑,判断是否能够处理当前请求
    • 如果可以处理,则处理请求并终止传递
    • 如果不能处理,则传递给后继处理器
  3. 构建处理链

    • 创建处理器实例
    • 按顺序链接处理器,形成处理链
    • 可结合建造者模式简化链的构建
  4. 客户端使用

    • 创建请求对象
    • 将请求提交给处理链的第一个处理器
    • 无需关心具体由哪个处理器处理

3.2 UML类图

角色说明

  • Handler (抽象处理器):定义处理请求的接口,维护后继处理器引用
  • ConcreteHandler (具体处理器):实现处理逻辑,处理可处理的请求,否则传递
  • Client (客户端):创建处理链并提交请求
  • Request (请求):封装请求信息和数据

3.3 代码示例

背景

以金额审批为例

  • 角色包括经理、总监、CEO,对于不同金额有不同处理结果
  • 实现上抽了一层AbstractHandler,配合模版方法

处理器接口

java 复制代码
public interface Handler {  
    /**  
     * @param request 请求  
     * @description 处理请求  
     * @author bigHao  
     * @date 2026/1/28  
     **/    
     void handleRequest(Request request);  
  
    /**  
     * @param next 下个处理器  
     * @description 设置下一个处理器  
     * @author bigHao  
     * @date 2026/1/28  
     **/    
     void setNext(Handler next);  
}

处理器基础实现

java 复制代码
public abstract class AbstractHandler implements Handler {  
  
    protected String name;  
  
    protected Handler nextHandler;  
  
    public AbstractHandler(String name) {  
        this.name = name;  
    }  
  
    @Override  
    public void handleRequest(Request request) {  
        if (canHandle(request)) {  
            System.out.println(STR."\{name} 可以处理 ");  
            process(request);  
        } else {  
            System.out.println(STR."\{name} 不可以处理 ");  
            nextHandler.handleRequest(request);  
        }  
    }  
  
    @Override  
    public void setNext(Handler next) {  
        this.nextHandler = next;  
    }  
  
  
    /**  
     * @param request 请求  
     * @return boolean 结果  
     * @description 是否可以处理  
     * @author bigHao  
     * @date 2026/1/28  
     **/    
     abstract boolean canHandle(Request request);  
  
    /**  
     * @param request 请求  
     * @description 执行请求  
     * @author bigHao  
     * @date 2026/1/28  
     **/    
     abstract void process(Request request);  
}

处理器子类

java 复制代码
public class ManagerHandler extends AbstractHandler {  
    public ManagerHandler(String name) {  
        super(name);  
    }  
  
    @Override  
    boolean canHandle(Request request) {  
        return request.getAmount() <= 1000;  
    }  
  
    @Override  
    void process(Request request) {  
        System.out.println("经理已经处理");  
    }  
}

public class DirectorHandler extends AbstractHandler {  
    public DirectorHandler(String name) {  
        super(name);  
    }  
  
    @Override  
    boolean canHandle(Request request) {  
        return request.getAmount() <= 10000;  
    }  
  
    @Override  
    void process(Request request) {  
        System.out.println(name + "已经处理");  
    }  
}

public class CEOHandler extends AbstractHandler {  
    public CEOHandler(String name) {  
        super(name);  
    }  
  
    @Override  
    boolean canHandle(Request request) {  
        return true;  
    }  
  
    @Override  
    void process(Request request) {  
        System.out.println(name + "已经处理");  
    }  
}

辅助类

java 复制代码
public class Request {  
    private int amount;  
  
    public Request(int amount) {  
        this.amount = amount;  
    }  
  
    public int getAmount() {  
        return amount;  
    }  
  
    public void setAmount(int amount) {  
        this.amount = amount;  
    }  
}

测试

java 复制代码
public class Client {  
    static void main() {  
        // 设置调用链  
        Handler manager = new ManagerHandler("张经理");  
        Handler director = new DirectorHandler("李总监");  
        Handler ceo = new CEOHandler("王CEO");  
  
        manager.setNext(director);  
        director.setNext(ceo);  
        Request request = new Request(2000);  
  
        manager.handleRequest(request);  
    }  
}

结果

复制代码
张经理 不可以处理 
李总监 可以处理 
李总监已经处理

4. 优缺点

4.1 优点

高内聚低耦合

  • 发送者与接收者解耦,发送者无需知道具体处理器
  • 处理器之间松耦合,可以独立变化和复用

复用性与可维护性

  • 处理器职责单一,易于复用
  • 可以动态添加、删除或修改处理器顺序,扩展性好
  • 符合开闭原则,新增处理器无需修改现有代码

灵活性与可读性

  • 处理流程清晰可见,易于理解和调试
  • 可以灵活组合处理器形成不同的处理链

4.2 缺点

性能与稳定性

  • 链过长可能影响性能,请求需要遍历多个处理器
  • 如果链配置不当,请求可能无法被处理(丢失请求)
  • 调试较困难,需要跟踪请求在链中的传递过程

其他考虑

  • 需要确保链中至少有一个处理器能处理请求,否则请求丢失
  • 处理器之间的顺序依赖可能隐含业务逻辑,不易察觉

5. 源码分析

有兴趣可以了解下Spring MVC中的责任链模式,我计划后面专门整理Spring相关内容


参考:

相关推荐
西岸行者2 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意2 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码2 天前
嵌入式学习路线
学习
毛小茛2 天前
计算机系统概论——校验码
学习
babe小鑫2 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms2 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下2 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。2 天前
2026.2.25监控学习
学习
im_AMBER2 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J2 天前
从“Hello World“ 开始 C++
c语言·c++·学习