设计模式之责任链

用「公司审批流程」讲透核心逻辑

责任链模式的讲解沿用「生活场景→角色映射→代码实现→核心总结」的结构,避免 "为了用模式而用模式",聚焦实际业务价值。

一、先看一个你肯定懂的生活场景

假设你在公司申请请假,流程是这样的:

  • 请假 1 天以内:部门经理直接审批;
  • 请假 1-3 天(含 3 天):部门经理无权审批,传给总监审批;
  • 请假 3 天以上:总监也无权审批,传给总经理审批;
  • 没有审批者能处理时(比如请假 100 天,超出所有权限),申请被驳回。

这个流程就是「责任链模式」的天然原型:

  • 「请假申请」是「请求」;
  • 「部门经理、总监、总经理」是「处理者」,按顺序连成一条「链」;
  • 你(申请人)只需要把请假申请交给「链的第一个处理者(部门经理)」,不用关心谁最终审批,也不用知道链上有多少人 ------ 这就是责任链的核心:解耦请求发送者和接收者

二、责任链模式的核心角色(对应审批场景)

不管是请假审批,还是 Web 开发的过滤器,责任链的核心角色永远只有 3 个,和场景一一对应:

模式角色 对应请假场景中的角色 核心职责
抽象处理者(Handler) 抽象审批者(AbstractApprover) 定义处理请求的接口(比如 "审批请假"),持有「下一个处理者」的引用(比如经理知道下一个是总监)。
具体处理者(ConcreteHandler) 部门经理、总监、总经理 实现抽象接口,判断自己能否处理请求:能处理就直接处理,不能就传给下一个处理者。
客户端(Client) 请假的员工 创建所有处理者,串联成链(比如指定 "经理→总监→总经理"),发起请求(提交请假申请)。

核心逻辑一句话:请求沿着链传递,直到被处理或链结束(两种情况:要么有人处理,要么无人处理被驳回)。

三、代码实现:把请假流程写成可运行的代码

我们用 Java 实现这个请假审批流程,代码简化且贴近业务,每个步骤都带注释,比日志例子更易理解:

步骤 1:定义抽象处理者(抽象审批者)

统一所有审批者的行为规范,包含「处理请求」和「设置下一个审批者」的核心方法:

java

运行

复制代码
// 抽象处理者:抽象审批者
abstract class AbstractApprover {
    // 下一个审批者(责任链的"链节")
    protected AbstractApprover nextApprover;
    // 审批者名称(方便打印日志)
    protected String name;

    public AbstractApprover(String name) {
        this.name = name;
    }

    // 设置下一个审批者(串联链)
    public void setNextApprover(AbstractApprover nextApprover) {
        this.nextApprover = nextApprover;
    }

    // 核心方法:处理请假请求(子类必须实现)
    public abstract void processLeaveRequest(LeaveRequest request);
}

步骤 2:定义请求对象(请假申请)

封装请求的核心信息,避免参数零散(实际开发中可扩展更多字段,比如请假原因、申请人部门):

java

运行

复制代码
// 请求对象:请假申请
class LeaveRequest {
    private String applicant; // 申请人
    private int days; // 请假天数

    public LeaveRequest(String applicant, int days) {
        this.applicant = applicant;
        this.days = days;
    }

    // getter方法(方便审批者获取信息)
    public String getApplicant() { return applicant; }
    public int getDays() { return days; }
}

步骤 3:实现具体处理者(3 个审批者)

每个审批者只关注自己的「审批权限」,无权则直接传递给下一个,逻辑清晰不冗余:

java

运行

复制代码
// 具体处理者1:部门经理(审批1天以内)
class DeptManager extends AbstractApprover {
    public DeptManager(String name) {
        super(name);
    }

    @Override
    public void processLeaveRequest(LeaveRequest request) {
        int days = request.getDays();
        String applicant = request.getApplicant();

        // 自己能处理的情况:1天以内
        if (days <= 1) {
            System.out.println(String.format("部门经理【%s】审批通过:%s请假%d天(1天内权限)", 
                    name, applicant, days));
        } else {
            // 无权处理,传给下一个审批者
            System.out.println(String.format("部门经理【%s】无权审批:%s请假%d天,转交总监", 
                    name, applicant, days));
            if (nextApprover != null) {
                nextApprover.processLeaveRequest(request);
            } else {
                // 没有下一个处理者,请求被驳回
                System.out.println("审批链断裂,请假申请驳回");
            }
        }
    }
}

// 具体处理者2:总监(审批1-3天)
class Director extends AbstractApprover {
    public Director(String name) {
        super(name);
    }

    @Override
    public void processLeaveRequest(LeaveRequest request) {
        int days = request.getDays();
        String applicant = request.getApplicant();

        if (days > 1 && days <= 3) {
            System.out.println(String.format("总监【%s】审批通过:%s请假%d天(1-3天权限)", 
                    name, applicant, days));
        } else {
            System.out.println(String.format("总监【%s】无权审批:%s请假%d天,转交总经理", 
                    name, applicant, days));
            if (nextApprover != null) {
                nextApprover.processLeaveRequest(request);
            } else {
                System.out.println("审批链断裂,请假申请驳回");
            }
        }
    }
}

// 具体处理者3:总经理(审批3天以上)
class GeneralManager extends AbstractApprover {
    public GeneralManager(String name) {
        super(name);
    }

    @Override
    public void processLeaveRequest(LeaveRequest request) {
        int days = request.getDays();
        String applicant = request.getApplicant();

        if (days > 3) {
            System.out.println(String.format("总经理【%s】审批通过:%s请假%d天(3天以上权限)", 
                    name, applicant, days));
        } else {
            // 理论上不会走到这(因为前两个审批者已经处理了3天内的请求)
            System.out.println(String.format("总经理【%s】无权审批:%s请假%d天,无后续审批者", 
                    name, applicant, days));
        }
    }
}

步骤 4:客户端(申请人)创建链并发起请求

客户端只做两件事:1. 把审批者连成链;2. 提交请求给链的第一个节点,不用管后续流程:

java

运行

复制代码
public class ChainOfResponsibilityDemo {
    public static void main(String[] args) {
        // 1. 创建3个具体处理者(审批者)
        AbstractApprover deptManager = new DeptManager("张三");
        AbstractApprover director = new Director("李四");
        AbstractApprover gm = new GeneralManager("王五");

        // 2. 串联成责任链:部门经理 → 总监 → 总经理
        deptManager.setNextApprover(director);
        director.setNextApprover(gm);

        // 3. 发起3个不同的请假请求(测试链的处理逻辑)
        System.out.println("=== 第一个请求:请假1天 ===");
        deptManager.processLeaveRequest(new LeaveRequest("小明", 1));

        System.out.println("\n=== 第二个请求:请假2天 ===");
        deptManager.processLeaveRequest(new LeaveRequest("小红", 2));

        System.out.println("\n=== 第三个请求:请假5天 ===");
        deptManager.processLeaveRequest(new LeaveRequest("小刚", 5));
    }
}

四、运行结果:直观看到请求传递过程

plaintext

复制代码
=== 第一个请求:请假1天 ===
部门经理【张三】审批通过:小明请假1天(1天内权限)

=== 第二个请求:请假2天 ===
部门经理【张三】无权审批:小红请假2天,转交总监
总监【李四】审批通过:小红请假2天(1-3天权限)

=== 第三个请求:请假5天 ===
部门经理【张三】无权审批:小刚请假5天,转交总监
总监【李四】无权审批:小刚请假5天,转交总经理
总经理【王五】审批通过:小刚请假5天(3天以上权限)

这个结果和我们生活中的审批流程完全一致,你能清晰看到:请求沿着链传递,直到找到能处理它的节点,客户端(申请人)全程只对接了部门经理,根本不用关心后续是谁审批。

五、核心总结:责任链模式到底解决什么问题?

1. 核心价值(对应请假场景的好处)

  • 解耦:申请人不用记 "谁能批几天假",只需找第一个审批者(部门经理),减少沟通成本;
  • 灵活:如果公司新增 "副总监" 审批 2-5 天,只需新增一个ViceDirector类,修改链的顺序(部门经理→副总监→总监→总经理),不用改原有审批者的代码;
  • 简化对象:每个审批者只关心自己的权限,不用知道整个链的结构(比如部门经理不用知道总经理的存在)。

2. 缺点(实际开发中要注意)

  • 请求可能无人处理:比如请假 100 天,所有审批者都无权处理,此时需要在链的最后加一个 "默认处理者"(比如 HR 驳回);
  • 性能影响:如果链很长(比如 10 个审批者),请求要依次传递,会有轻微性能损耗;
  • 调试麻烦:如果请求传递出错(比如链断了),需要逐节点排查,不如直接调用直观。

3. 实际开发场景(不再是 "刻意用模式")

  • Web 开发的 Filter 链:比如 Tomcat 处理请求时,请求会经过多个 Filter(编码过滤、权限过滤、日志过滤),每个 Filter 处理完后传给下一个;
  • 框架的拦截器链:比如 Struts2、Spring MVC 的拦截器,请求先经过拦截器,再到 Controller;
  • 工作流引擎:比如 OA 系统的报销审批、合同审批,本质都是责任链的延伸(可动态配置链的节点)。

六、和策略模式的区别(避免混淆)

很多人会把责任链和策略模式搞混,用一句话区分:

  • 策略模式:多个处理方案选一个(比如出行选飞机 / 火车 / 汽车,只能选一种);
  • 责任链模式:多个处理者传一个请求(比如请假申请传给经理 / 总监 / 总经理,直到有人处理)。

简单说:策略模式是 "选择",责任链是 "传递"。

到这里,责任链模式的核心逻辑就讲透了 ------ 它不是一个 "刻意设计" 的复杂模式,而是生活中 "流程传递" 场景的代码抽象,核心就是「解耦发送者和接收者,让请求沿着链自动找到处理者」。

相关推荐
sxlishaobin9 小时前
设计模式之原型模式
设计模式·原型模式
范纹杉想快点毕业10 小时前
嵌入式通信核心架构:从状态机、环形队列到多协议融合
linux·运维·c语言·算法·设计模式
__万波__10 小时前
二十三种设计模式(二十)--解释器模式
java·设计模式·解释器模式
攀登的牵牛花11 小时前
前端向架构突围系列 - 架构方法(一):概述 4+1 视图模型
前端·设计模式·架构
雲墨款哥11 小时前
从一行好奇的代码说起:React的 useEffect 到底是不是生命周期?
前端·react.js·设计模式
cultivator12948013 小时前
设计原则和设计模式助记
设计模式
enjoy编程14 小时前
Spring boot 4 探究netty的关键知识点
spring boot·设计模式·reactor·netty·多线程
用户938169125536014 小时前
Head First 单例模式
后端·设计模式
a35354138215 小时前
设计模式-桥接模式
c++·设计模式·桥接模式
sxlishaobin15 小时前
设计模式之外观模式
java·设计模式·外观模式