5分钟实战掌握责任链模式(Chain of Responsibility Pattern):从 “if-else 审批地狱” 到 “流水线式请求处理”
当你在电商系统中写订单审批逻辑时,是不是遇到过这样的噩梦:订单金额小于 1000 元组长审批,1000-5000 元经理审批,5000-20000 元总监审批,20000 元以上 CEO 审批 —— 每加一个审批级别,就要在代码里塞一个if-else,最后代码变成了 “千层饼”,改一个审批金额就要动整个方法。
这时候,责任链模式(Chain of Responsibility Pattern)就是救星。它的核心是 “将请求的发送者和接收者解耦,让多个接收者都有机会处理请求,形成一条处理链”—— 就像公司的审批流程,订单从组长开始,能批就批,不能批就传给经理,经理不能批传给总监,直到有人处理为止。每个审批人只关心自己的权限范围,完全不用知道其他人的存在。
本文将以 “电商订单多级审批” 为实战场景,带你吃透责任链模式的设计思想、落地步骤和避坑指南,让你的代码从 “if-else 堆” 变成 “优雅的流水线”。
一、为什么需要责任链模式?先踩传统实现的 “坑”
先明确实战场景:电商平台的订单审批功能,要求:
- 审批规则:
- 订单金额 < 1000 元:组长审批
- 1000 元 ≤ 金额 < 5000 元:经理审批
- 5000 元 ≤ 金额 < 20000 元:总监审批
- 金额 ≥ 20000 元:CEO 审批
- 支持动态调整审批规则(如新增副总裁审批级别);
- 审批人职责单一:每个审批人只处理自己权限范围内的订单;
- 审批流程可追溯:记录每个审批人的处理结果。
传统实现的 “灾难现场”:用 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 大 “致命问题”
- 代码耦合严重:所有审批逻辑写在一个方法里,审批人、审批金额硬编码,改一个审批规则就要动整个方法;
- 违反开闭原则:新增 “副总裁” 审批级别(如 10000-20000 元),需要修改
approveOrder方法,添加新的if-else分支; - 职责不单一:
TraditionalOrderApprovalService既要判断金额,又要调用审批人,承担了过多职责; - 无法动态调整流程:如果想把 “总监审批” 的金额上限从 20000 元改成 30000 元,或者调整审批顺序(如先经理后组长),必须修改代码,无法在运行时动态调整。
二、责任链模式核心揭秘:让请求在 “流水线” 上传递
责任链模式的本质是 “将每个处理者封装成独立的对象,通过链式结构连接起来,请求沿着链传递,直到有处理者处理它为止”。
1. 责任链模式核心结构(类图)

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:扩展后的运行结果
=== 审批订单5:15000元(新增副总裁后)===
[组长] 订单金额15000元超出权限,转交给经理审批
[经理] 订单金额15000元超出权限,转交给总监审批
[总监] 订单金额15000元超出权限,转交给副总裁审批
[副总裁] 孙七 审批通过订单:ORDER_005,金额:15000元
=== 审批订单6:35000元(新增副总裁后)===
[组长] 订单金额35000元超出权限,转交给经理审批
[经理] 订单金额35000元超出权限,转交给总监审批
[总监] 订单金额35000元超出权限,转交给副总裁审批
[副总裁] 订单金额35000元超出权限,转交给CEO审批
[CEO] 赵六 审批通过订单:ORDER_006,金额:35000元
完美!新增 “副总裁” 审批级别时:
- 没有修改
TeamLeaderHandler、ManagerHandler等任何原有处理者的代码; - 没有修改
ApprovalHandler抽象类的代码; - 仅新增了一个
VicePresidentHandler类,并在客户端调整了责任链的组装顺序; - 完全符合 “开闭原则”,扩展功能对原有代码零侵入。
五、责任链模式实战避坑指南
责任链模式虽好,但实战中容易踩以下 3 个坑,必须注意:
1. 避免责任链过长导致性能问题
如果责任链包含过多处理者(如 10 个以上),请求需要经过多次传递才能被处理,会影响性能。
解决方案:
- 控制责任链的长度(一般不超过 5 个处理者);
- 对于高频请求,可以使用 “哈希表 + 责任链” 的混合模式,先通过哈希表快速定位到可能的处理者,再传递请求。
2. 避免循环引用导致死循环
如果责任链的最后一个处理者的nextHandler指向了第一个处理者,会导致请求在链上无限循环,最终栈溢出。
解决方案:
- 组装责任链时,确保最后一个处理者的
nextHandler为null; - 在
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); - 特点:双向责任链,入站事件从头部向尾部传递,出站事件从尾部向头部传递。
七、总结:责任链模式的 “最佳应用场景”
当你遇到以下场景时,责任链模式就是 “最优解”:
- 多个对象可以处理同一个请求,且处理者不确定:如订单审批、请假审批、报销审批等流程;
- 需要动态指定处理请求的对象:如根据不同的用户角色动态调整审批流程;
- 需要在不明确指定接收者的情况下,向多个对象中的一个发送请求:如事件处理系统、消息分发系统;
- 需要将请求的处理逻辑分散到多个处理者中,实现职责单一:如请求的日志记录、权限校验、参数校验等。
责任链模式的核心不是 “链” 本身,而是 “解耦请求的发送者和接收者”—— 让每个处理者只关心自己的职责,请求在链上自动传递,直到被处理。下次再写 “if-else 堆” 的审批逻辑时,不妨试试责任链模式,让代码从 “千层饼” 变成 “优雅的流水线”。
上一篇:代理模式(Proxy Pattern)实战:从 “代码耦合泥潭” 到 “功能横切自如”,解锁业务增强的优雅姿势
– 欢迎点赞、关注、转发、收藏【技术咖啡馆C】,各大平台同名,不定时分享技术文章。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)