当你在电商系统中写订单审批逻辑时,是不是遇到过这样的噩梦:订单金额小于 1000 元组长审批,1000-5000 元经理审批,5000-20000 元总监审批,20000 元以上 CEO 审批 —— 每加一个审批级别,就要在代码里塞一个if-else,最后代码变成了 “千层饼”,改一个审批金额就要动整个方法。

这时候,责任链模式(Chain of Responsibility Pattern)就是救星。它的核心是 “将请求的发送者和接收者解耦,让多个接收者都有机会处理请求,形成一条处理链”—— 就像公司的审批流程,订单从组长开始,能批就批,不能批就传给经理,经理不能批传给总监,直到有人处理为止。每个审批人只关心自己的权限范围,完全不用知道其他人的存在。

本文将以 “电商订单多级审批” 为实战场景,带你吃透责任链模式的设计思想、落地步骤和避坑指南,让你的代码从 “if-else 堆” 变成 “优雅的流水线”。

一、为什么需要责任链模式?先踩传统实现的 “坑”

先明确实战场景:电商平台的订单审批功能,要求:

  1. 审批规则:
    • 订单金额 < 1000 元:组长审批
    • 1000 元 ≤ 金额 < 5000 元:经理审批
    • 5000 元 ≤ 金额 < 20000 元:总监审批
    • 金额 ≥ 20000 元:CEO 审批
  2. 支持动态调整审批规则(如新增副总裁审批级别);
  3. 审批人职责单一:每个审批人只处理自己权限范围内的订单;
  4. 审批流程可追溯:记录每个审批人的处理结果。

传统实现的 “灾难现场”:用 if-else 硬堆审批逻辑

如果不使用责任链模式,我们会写一个OrderApprovalService,把所有审批逻辑塞进approveOrder方法里,用if-else判断订单金额,调用不同审批人的方法:

import java.math.BigDecimal;
import java.util.UUID;

// 订单类
@Data
@AllArgsConstructor
class Order {
    private String orderId;
    private BigDecimal amount; // 订单金额
    private String applicant; // 申请人
}

// 审批人类(组长、经理、总监、CEO)
class Approver {
    private String name;
    private String level;

    public Approver(String name, String level) {
        this.name = name;
        this.level = level;
    }

    // 审批方法
    public void approve(Order order) {
        System.out.println("[" + level + "] " + name + " 审批通过订单:" + order.getOrderId());
    }
}

// 传统订单审批服务:用if-else硬堆审批逻辑
class TraditionalOrderApprovalService {
    // 初始化所有审批人
    private final Approver teamLeader = new Approver("张三", "组长");
    private final Approver manager = new Approver("李四", "经理");
    private final Approver director = new Approver("王五", "总监");
    private final Approver ceo = new Approver("赵六", "CEO");

    public void approveOrder(Order order) {
        BigDecimal amount = order.getAmount();

        // 用if-else判断金额,调用对应审批人
        if (amount.compareTo(new BigDecimal("1000")) < 0) {
            teamLeader.approve(order);
        } else if (amount.compareTo(new BigDecimal("5000")) < 0) {
            manager.approve(order);
        } else if (amount.compareTo(new BigDecimal("20000")) < 0) {
            director.approve(order);
        } else {
            ceo.approve(order);
        }
    }
}

// 客户端调用
public class TraditionalClient {
    public static void main(String[] args) {
        TraditionalOrderApprovalService service = new TraditionalOrderApprovalService();
        
        // 测试不同金额的订单
        Order order1 = new Order("ORDER_001", new BigDecimal("800"), "小明");
        Order order2 = new Order("ORDER_002", new BigDecimal("3000"), "小红");
        Order order3 = new Order("ORDER_003", new BigDecimal("15000"), "小刚");
        Order order4 = new Order("ORDER_004", new BigDecimal("50000"), "小丽");

        service.approveOrder(order1);
        service.approveOrder(order2);
        service.approveOrder(order3);
        service.approveOrder(order4);
    }
}

传统实现的 4 大 “致命问题”

  1. 代码耦合严重:所有审批逻辑写在一个方法里,审批人、审批金额硬编码,改一个审批规则就要动整个方法;
  2. 违反开闭原则:新增 “副总裁” 审批级别(如 10000-20000 元),需要修改approveOrder方法,添加新的if-else分支;
  3. 职责不单一TraditionalOrderApprovalService既要判断金额,又要调用审批人,承担了过多职责;
  4. 无法动态调整流程:如果想把 “总监审批” 的金额上限从 20000 元改成 30000 元,或者调整审批顺序(如先经理后组长),必须修改代码,无法在运行时动态调整。

二、责任链模式核心揭秘:让请求在 “流水线” 上传递

责任链模式的本质是 “将每个处理者封装成独立的对象,通过链式结构连接起来,请求沿着链传递,直到有处理者处理它为止”

1. 责任链模式核心结构(类图)

UML

2. 3 个核心角色的职责(对应订单审批场景)

角色 核心职责 示例(订单审批场景)
抽象处理者(Handler) 定义处理请求的接口,持有下一个处理者的引用,提供设置下一个处理者的方法 ApprovalHandler(审批处理者抽象类)
具体处理者(ConcreteHandler) 实现处理请求的逻辑,判断自己是否能处理请求,能则处理,不能则传给下一个处理者 TeamLeaderHandler(组长)、ManagerHandler(经理)等
客户端(Client) 创建处理者对象,组装成责任链,向链的第一个处理者发送请求 订单系统的下单模块

3. 责任链模式的 “3 大优势”(对比传统实现)

优势 传统实现的问题 责任链模式的解决方式
解耦发送者与接收者 客户端需要知道所有审批人的存在和权限 客户端只需要知道链的第一个处理者,不用关心谁会处理请求
符合开闭原则 新增审批级别需要修改原有代码 新增审批级别只需新增一个具体处理者类,不碰旧代码
职责单一 一个类承担所有审批逻辑 每个具体处理者只处理自己权限范围内的请求,职责单一
动态调整流程 审批流程硬编码,无法动态调整 可以在运行时动态添加、删除、修改处理者,调整链的顺序

三、实战:用责任链模式重构订单审批流程

基于上述结构,我们对 “电商订单审批” 进行重构,核心是将每个审批人封装成独立的处理者,通过链式结构连接起来。

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

抽象处理者定义审批的统一接口,持有下一个处理者的引用,并提供设置下一个处理者的方法:

import java.math.BigDecimal;

/**
 * 抽象处理者:审批处理者的统一接口
 */
public abstract class ApprovalHandler {
    // 持有下一个处理者的引用
    protected ApprovalHandler nextHandler;

    /**
     * 设置下一个处理者(构建责任链)
     */
    public void setNextHandler(ApprovalHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    /**
     * 处理审批请求(抽象方法,由具体处理者实现)
     * @param order 待审批的订单
     */
    public abstract void handleRequest(Order order);

    // 工具方法:获取审批人名称(由子类实现)
    protected abstract String getApproverName();
}

步骤 2:实现具体处理者(ConcreteHandler)—— 每个审批人一个类

每个审批人都是一个独立的具体处理者,只处理自己权限范围内的订单,不能处理则传给下一个处理者。

2.1 组长审批处理者(TeamLeaderHandler)
import java.math.BigDecimal;

/**
 * 具体处理者1:组长审批(金额 < 1000元)
 */
public class TeamLeaderHandler extends ApprovalHandler {
    private static final BigDecimal MAX_AMOUNT = new BigDecimal("1000");

    @Override
    public void handleRequest(Order order) {
        if (order.getAmount().compareTo(MAX_AMOUNT) < 0) {
            // 能处理:执行审批逻辑
            System.out.println("[组长] " + getApproverName() + " 审批通过订单:" + order.getOrderId() 
                               + ",金额:" + order.getAmount() + "元");
        } else {
            // 不能处理:传给下一个处理者
            System.out.println("[组长] 订单金额" + order.getAmount() + "元超出权限,转交给经理审批");
            if (nextHandler != null) {
                nextHandler.handleRequest(order);
            } else {
                System.out.println("[错误] 没有下一个审批人,订单无法审批");
            }
        }
    }

    @Override
    protected String getApproverName() {
        return "张三";
    }
}
2.2 经理审批处理者(ManagerHandler)
import java.math.BigDecimal;

/**
 * 具体处理者2:经理审批(1000元 ≤ 金额 < 5000元)
 */
public class ManagerHandler extends ApprovalHandler {
    private static final BigDecimal MIN_AMOUNT = new BigDecimal("1000");
    private static final BigDecimal MAX_AMOUNT = new BigDecimal("5000");

    @Override
    public void handleRequest(Order order) {
        if (order.getAmount().compareTo(MIN_AMOUNT) >= 0 
            && order.getAmount().compareTo(MAX_AMOUNT) < 0) {
            System.out.println("[经理] " + getApproverName() + " 审批通过订单:" + order.getOrderId() 
                               + ",金额:" + order.getAmount() + "元");
        } else {
            System.out.println("[经理] 订单金额" + order.getAmount() + "元超出权限,转交给总监审批");
            if (nextHandler != null) {
                nextHandler.handleRequest(order);
            } else {
                System.out.println("[错误] 没有下一个审批人,订单无法审批");
            }
        }
    }

    @Override
    protected String getApproverName() {
        return "李四";
    }
}
2.3 总监审批处理者(DirectorHandler)
import java.math.BigDecimal;

/**
 * 具体处理者3:总监审批(5000元 ≤ 金额 < 20000元)
 */
public class DirectorHandler extends ApprovalHandler {
    private static final BigDecimal MIN_AMOUNT = new BigDecimal("5000");
    private static final BigDecimal MAX_AMOUNT = new BigDecimal("20000");

    @Override
    public void handleRequest(Order order) {
        if (order.getAmount().compareTo(MIN_AMOUNT) >= 0 
            && order.getAmount().compareTo(MAX_AMOUNT) < 0) {
            System.out.println("[总监] " + getApproverName() + " 审批通过订单:" + order.getOrderId() 
                               + ",金额:" + order.getAmount() + "元");
        } else {
            System.out.println("[总监] 订单金额" + order.getAmount() + "元超出权限,转交给CEO审批");
            if (nextHandler != null) {
                nextHandler.handleRequest(order);
            } else {
                System.out.println("[错误] 没有下一个审批人,订单无法审批");
            }
        }
    }

    @Override
    protected String getApproverName() {
        return "王五";
    }
}
2.4 CEO 审批处理者(CEOHandler)
import java.math.BigDecimal;

/**
 * 具体处理者4:CEO审批(金额 ≥ 20000元)
 */
public class CEOHandler extends ApprovalHandler {
    private static final BigDecimal MIN_AMOUNT = new BigDecimal("20000");

    @Override
    public void handleRequest(Order order) {
        if (order.getAmount().compareTo(MIN_AMOUNT) >= 0) {
            System.out.println("[CEO] " + getApproverName() + " 审批通过订单:" + order.getOrderId() 
                               + ",金额:" + order.getAmount() + "元");
        } else {
            // CEO是最后一个处理者,没有下一个
            System.out.println("[CEO] 订单金额" + order.getAmount() + "元不符合审批范围,拒绝审批");
        }
    }

    @Override
    protected String getApproverName() {
        return "赵六";
    }
}

步骤 3:订单类(复用之前的,补充必要方法)

import lombok.AllArgsConstructor;
import lombok.Data;
import java.math.BigDecimal;

/**
 * 订单类:待审批的请求对象
 */
@Data
@AllArgsConstructor
public class Order {
    private String orderId;
    private BigDecimal amount; // 订单金额
    private String applicant; // 申请人
}

步骤 4:客户端调用 —— 组装责任链并发送请求

客户端负责创建处理者对象,组装成责任链(组长→经理→总监→CEO),然后向链的第一个处理者发送审批请求:

import java.math.BigDecimal;

/**
 * 责任链模式客户端:组装责任链并发送审批请求
 */
public class ChainOfResponsibilityClient {
    public static void main(String[] args) {
        // 1. 创建所有处理者对象
        ApprovalHandler teamLeader = new TeamLeaderHandler();
        ApprovalHandler manager = new ManagerHandler();
        ApprovalHandler director = new DirectorHandler();
        ApprovalHandler ceo = new CEOHandler();

        // 2. 组装责任链:组长 → 经理 → 总监 → CEO
        teamLeader.setNextHandler(manager);
        manager.setNextHandler(director);
        director.setNextHandler(ceo);

        // 3. 创建测试订单
        Order order1 = new Order("ORDER_001", new BigDecimal("800"), "小明");
        Order order2 = new Order("ORDER_002", new BigDecimal("3000"), "小红");
        Order order3 = new Order("ORDER_003", new BigDecimal("15000"), "小刚");
        Order order4 = new Order("ORDER_004", new BigDecimal("50000"), "小丽");

        // 4. 向链的第一个处理者(组长)发送请求
        System.out.println("=== 审批订单1:800元 ===");
        teamLeader.handleRequest(order1);

        System.out.println("\n=== 审批订单2:3000元 ===");
        teamLeader.handleRequest(order2);

        System.out.println("\n=== 审批订单3:15000元 ===");
        teamLeader.handleRequest(order3);

        System.out.println("\n=== 审批订单4:50000元 ===");
        teamLeader.handleRequest(order4);
    }
}

步骤 5:运行结果(清晰的审批流程)

=== 审批订单1:800元 ===
[组长] 张三 审批通过订单:ORDER_001,金额:800元

=== 审批订单2:3000元 ===
[组长] 订单金额3000元超出权限,转交给经理审批
[经理] 李四 审批通过订单:ORDER_002,金额:3000元

=== 审批订单3:15000元 ===
[组长] 订单金额15000元超出权限,转交给经理审批
[经理] 订单金额15000元超出权限,转交给总监审批
[总监] 王五 审批通过订单:ORDER_003,金额:15000元

=== 审批订单4:50000元 ===
[组长] 订单金额50000元超出权限,转交给经理审批
[经理] 订单金额50000元超出权限,转交给总监审批
[总监] 订单金额50000元超出权限,转交给CEO审批
[CEO] 赵六 审批通过订单:ORDER_004,金额:50000元

从结果可见:

  • 每个审批人只处理自己权限范围内的订单,超出权限则自动传给下一个;
  • 审批流程清晰可追溯,能看到订单在链上的传递过程;
  • 客户端只需要向第一个处理者发送请求,不用关心谁会处理。

四、扩展实战:新增 “副总裁” 审批级别,验证开闭原则

现在,我们要新增 “副总裁” 审批级别(10000-30000 元由副总裁审批,30000 元以上由 CEO 审批),看看责任链模式如何做到 “不修改旧代码,只加新代码”。

步骤 1:新增具体处理者 ——VicePresidentHandler

import java.math.BigDecimal;

/**
 * 新增具体处理者:副总裁审批(10000元 ≤ 金额 < 30000元)
 * 无需修改任何原有代码,仅新增一个类
 */
public class VicePresidentHandler extends ApprovalHandler {
    private static final BigDecimal MIN_AMOUNT = new BigDecimal("10000");
    private static final BigDecimal MAX_AMOUNT = new BigDecimal("30000");

    @Override
    public void handleRequest(Order order) {
        if (order.getAmount().compareTo(MIN_AMOUNT) >= 0 
            && order.getAmount().compareTo(MAX_AMOUNT) < 0) {
            System.out.println("[副总裁] " + getApproverName() + " 审批通过订单:" + order.getOrderId() 
                               + ",金额:" + order.getAmount() + "元");
        } else {
            System.out.println("[副总裁] 订单金额" + order.getAmount() + "元超出权限,转交给CEO审批");
            if (nextHandler != null) {
                nextHandler.handleRequest(order);
            } else {
                System.out.println("[错误] 没有下一个审批人,订单无法审批");
            }
        }
    }

    @Override
    protected String getApproverName() {
        return "孙七";
    }
}

步骤 2:客户端调整责任链(仅修改组装逻辑,不碰原有处理者)

在客户端组装责任链时,将副总裁插入到总监和 CEO 之间:

// 1. 创建新增的副总裁处理者
ApprovalHandler vicePresident = new VicePresidentHandler();

// 2. 调整责任链:组长 → 经理 → 总监 → 副总裁 → CEO
teamLeader.setNextHandler(manager);
manager.setNextHandler(director);
director.setNextHandler(vicePresident); // 总监的下一个改为副总裁
vicePresident.setNextHandler(ceo); // 副总裁的下一个是CEO

步骤 3:测试新增后的审批流程

// 测试15000元订单(原总监审批,现副总裁审批)
Order order5 = new Order("ORDER_005", new BigDecimal("15000"), "小华");
System.out.println("\n=== 审批订单5:15000元(新增副总裁后)===");
teamLeader.handleRequest(order5);

// 测试35000元订单(原CEO审批,现仍由CEO审批)
Order order6 = new Order("ORDER_006", new BigDecimal("35000"), "小伟");
System.out.println("\n=== 审批订单6:35000元(新增副总裁后)===");
teamLeader.handleRequest(order6);

步骤 4:扩展后的运行结果

=== 审批订单515000元(新增副总裁后)===
[组长] 订单金额15000元超出权限,转交给经理审批
[经理] 订单金额15000元超出权限,转交给总监审批
[总监] 订单金额15000元超出权限,转交给副总裁审批
[副总裁] 孙七 审批通过订单:ORDER_005,金额:15000=== 审批订单635000元(新增副总裁后)===
[组长] 订单金额35000元超出权限,转交给经理审批
[经理] 订单金额35000元超出权限,转交给总监审批
[总监] 订单金额35000元超出权限,转交给副总裁审批
[副总裁] 订单金额35000元超出权限,转交给CEO审批
[CEO] 赵六 审批通过订单:ORDER_006,金额:35000

完美!新增 “副总裁” 审批级别时:

  • 没有修改TeamLeaderHandlerManagerHandler等任何原有处理者的代码;
  • 没有修改ApprovalHandler抽象类的代码;
  • 仅新增了一个VicePresidentHandler类,并在客户端调整了责任链的组装顺序;
  • 完全符合 “开闭原则”,扩展功能对原有代码零侵入。

五、责任链模式实战避坑指南

责任链模式虽好,但实战中容易踩以下 3 个坑,必须注意:

1. 避免责任链过长导致性能问题

如果责任链包含过多处理者(如 10 个以上),请求需要经过多次传递才能被处理,会影响性能。

解决方案

  • 控制责任链的长度(一般不超过 5 个处理者);
  • 对于高频请求,可以使用 “哈希表 + 责任链” 的混合模式,先通过哈希表快速定位到可能的处理者,再传递请求。

2. 避免循环引用导致死循环

如果责任链的最后一个处理者的nextHandler指向了第一个处理者,会导致请求在链上无限循环,最终栈溢出。

解决方案

  • 组装责任链时,确保最后一个处理者的nextHandlernull
  • handleRequest方法中添加循环检测(如记录请求传递次数,超过阈值则抛出异常)。

3. 避免请求无人处理

如果责任链上没有任何处理者能处理请求,会导致请求丢失,业务逻辑出错。

解决方案

  • 在链的最后添加一个 “兜底处理者”(如DefaultHandler),处理所有未被其他处理者处理的请求;
  • handleRequest方法中,如果没有下一个处理者且自己不能处理,抛出明确的异常或记录错误日志。

4. 区分 “纯责任链” 和 “不纯责任链”

  • 纯责任链:一个请求只能被一个处理者处理,处理后立即终止传递(如本文的订单审批);

  • 不纯责任链

    :一个请求可以被多个处理者处理,处理后继续传递(如 Servlet 的 Filter 链,每个 Filter 都能处理请求)。

    注意

    :根据业务场景选择合适的责任链类型,避免混淆。

六、责任链模式在主流框架中的应用

责任链模式在 Java 和框架中应用广泛,以下是你一定用过的经典场景:

1. Servlet 的 Filter 链(最经典的不纯责任链)

Java Web 中的Filter链是责任链模式的典型应用:

  • 抽象处理者:Filter接口;
  • 具体处理者:自定义的Filter(如登录 Filter、权限 Filter、日志 Filter);
  • 客户端:Servlet 容器(如 Tomcat);
  • 特点:不纯责任链,每个 Filter 都能处理请求和响应,处理后继续传递给下一个 Filter。
// 自定义Filter示例
public class LoginFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
            throws IOException, ServletException {
        // 前置处理:检查登录状态
        System.out.println("[LoginFilter] 检查用户登录状态");
        
        // 传递给下一个Filter
        chain.doFilter(request, response);
        
        // 后置处理:记录日志
        System.out.println("[LoginFilter] 请求处理完成");
    }
}

2. Spring MVC 的 Interceptor 拦截器链

Spring MVC 的HandlerInterceptor拦截器链也是责任链模式的应用:

  • 抽象处理者:HandlerInterceptor接口;
  • 具体处理者:自定义的拦截器(如权限拦截器、日志拦截器);
  • 特点:不纯责任链,支持前置处理(preHandle)、后置处理(postHandle)和完成后处理(afterCompletion)。

3. Netty 的 ChannelPipeline(网络请求处理链)

Netty 的ChannelPipeline是一个双向的责任链,用于处理网络请求的入站和出站事件:

  • 抽象处理者:ChannelHandler接口;
  • 具体处理者:自定义的ChannelHandler(如解码 Handler、编码 Handler、业务 Handler);
  • 特点:双向责任链,入站事件从头部向尾部传递,出站事件从尾部向头部传递。

七、总结:责任链模式的 “最佳应用场景”

当你遇到以下场景时,责任链模式就是 “最优解”:

  1. 多个对象可以处理同一个请求,且处理者不确定:如订单审批、请假审批、报销审批等流程;
  2. 需要动态指定处理请求的对象:如根据不同的用户角色动态调整审批流程;
  3. 需要在不明确指定接收者的情况下,向多个对象中的一个发送请求:如事件处理系统、消息分发系统;
  4. 需要将请求的处理逻辑分散到多个处理者中,实现职责单一:如请求的日志记录、权限校验、参数校验等。

责任链模式的核心不是 “链” 本身,而是 “解耦请求的发送者和接收者”—— 让每个处理者只关心自己的职责,请求在链上自动传递,直到被处理。下次再写 “if-else 堆” 的审批逻辑时,不妨试试责任链模式,让代码从 “千层饼” 变成 “优雅的流水线”。

上一篇:代理模式(Proxy Pattern)实战:从 “代码耦合泥潭” 到 “功能横切自如”,解锁业务增强的优雅姿势

– 欢迎点赞、关注、转发、收藏【技术咖啡馆C】,各大平台同名,不定时分享技术文章。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐