设计模式(十四)行为型:职责链模式详解
职责链模式(Chain of Responsibility Pattern)是 GoF 23 种设计模式中的行为型模式之一,其核心价值在于将多个处理对象(处理器)连接成一条链,使请求沿着链传递,直到被某个处理器处理为止。它解耦了请求的发送者与接收者,允许动态地组织处理流程,提升系统的灵活性与可扩展性。职责链模式是实现“开闭原则”的典范,广泛应用于审批流程(请假、报销)、事件处理(GUI 事件分发)、日志系统(多级日志处理器)、中间件管道(如 Web 框架的过滤器链)、异常处理、权限校验等需要多级判断或顺序处理的场景,是构建可配置、可插拔业务流程的关键架构模式。
一、详细介绍
职责链模式解决的是“一个请求可能由多个对象处理,但具体由谁处理在运行时决定”的问题。在传统设计中,客户端需要显式判断由哪个对象处理请求,导致代码中充斥条件判断(if-else 或 switch),难以维护和扩展。当处理逻辑变更或新增处理器时,客户端代码必须修改。
职责链模式通过将多个处理器组织成一条链,客户端只需将请求发送给链的首节点,后续传递由处理器自行决定。每个处理器都持有对下一个处理器的引用(或通过外部容器管理),并在处理请求时:
- 判断自己是否能处理该请求;
- 若能处理,则执行业务逻辑并结束;
- 若不能处理,则将请求转发给链中的下一个处理器;
- 若链尾仍未处理,则可选择丢弃或抛出异常。
该模式包含以下核心角色:
- Handler(抽象处理器):定义处理请求的接口,通常包含一个方法(如
handleRequest()
)和一个指向后继处理器的引用(successor
)。可以是抽象类或接口。 - ConcreteHandler(具体处理器):实现
Handler
接口,包含具体的处理逻辑。它决定是否处理当前请求,若不处理则将请求转发给后继。 - Client(客户端):创建处理器链,并向链的首节点发送请求。客户端不关心具体由哪个处理器处理,也不依赖具体处理器类型。
职责链的组织方式有两种:
- 显式链(Explicit Chain):每个处理器持有对下一个处理器的引用,形成链式结构。
- 中心化链(Centralized Chain):由一个容器(如
Chain
类)管理处理器列表,按顺序调用。
职责链模式的关键优势:
- 解耦请求发送者与接收者:客户端无需知道具体处理者。
- 增强系统灵活性:可动态添加、删除或重排处理器。
- 符合开闭原则:新增处理器无需修改现有代码。
- 支持多种处理逻辑:可实现“首个匹配即处理”或“全部处理”等策略。
与“状态模式”相比,职责链关注请求的传递与处理,状态模式关注对象行为随状态改变;与“观察者模式”相比,职责链是单向链式传递,观察者是广播式通知;与“策略模式”相比,职责链允许多个策略顺序参与,策略模式是单一策略选择。
二、职责链模式的UML表示
以下是职责链模式的标准 UML 类图:
图解说明:
Handler
定义处理接口和后继引用。ConcreteHandlerA/B/C
实现具体处理逻辑,可选择处理请求或转发。- 处理器通过
setSuccessor()
构成链。 - 客户端向链首发送请求,请求沿链传递。
三、一个简单的Java程序实例及其UML图
以下是一个公司请假审批系统的示例,展示不同级别的管理者对不同天数的请假请求进行审批。
Java 程序实例
// 请求类
class LeaveRequest {private String employee;private int days;private String reason;public LeaveRequest(String employee, int days, String reason) {this.employee = employee;this.days = days;this.reason = reason;}// Getter 方法public String getEmployee() { return employee; }public int getDays() { return days; }public String getReason() { return reason; }@Overridepublic String toString() {return "LeaveRequest{" +"employee='" + employee + '\'' +", days=" + days +", reason='" + reason + '\'' +'}';}
}// 抽象处理器:审批者
abstract class Approver {protected Approver successor;protected String name;protected String position;public Approver(String name, String position) {this.name = name;this.position = position;}public void setSuccessor(Approver successor) {this.successor = successor;}// 处理请求的抽象方法public abstract void handleRequest(LeaveRequest request);
}// 具体处理器:组长(可批1-3天)
class TeamLeader extends Approver {public TeamLeader(String name) {super(name, "Team Leader");}@Overridepublic void handleRequest(LeaveRequest request) {if (request.getDays() <= 3) {System.out.println("✅ [" + position + " " + name + "] 批准了 " + request.getEmployee() +" 的 " + request.getDays() + " 天请假申请。");} else if (successor != null) {System.out.println("⏭️ [" + position + " " + name + "] 无法处理,转交上级...");successor.handleRequest(request);}}
}// 具体处理器:部门经理(可批4-7天)
class DepartmentManager extends Approver {public DepartmentManager(String name) {super(name, "Department Manager");}@Overridepublic void handleRequest(LeaveRequest request) {if (request.getDays() <= 7) {System.out.println("✅ [" + position + " " + name + "] 批准了 " + request.getEmployee() +" 的 " + request.getDays() + " 天请假申请。");} else if (successor != null) {System.out.println("⏭️ [" + position + " " + name + "] 无法处理,转交上级...");successor.handleRequest(request);}}
}// 具体处理器:总经理(可批任意天数)
class GeneralManager extends Approver {public GeneralManager(String name) {super(name, "General Manager");}@Overridepublic void handleRequest(LeaveRequest request) {System.out.println("✅ [" + position + " " + name + "] 特批了 " + request.getEmployee() +" 的 " + request.getDays() + " 天请假申请。");}
}// 客户端使用示例
public class ChainOfResponsibilityDemo {public static void main(String[] args) {System.out.println("🏢 公司请假审批系统 - 职责链模式示例\n");// 创建处理器链Approver teamLeader = new TeamLeader("张组长");Approver deptManager = new DepartmentManager("李经理");Approver gm = new GeneralManager("王总");// 构建链:组长 -> 部门经理 -> 总经理teamLeader.setSuccessor(deptManager);deptManager.setSuccessor(gm);// 模拟不同请假请求LeaveRequest req1 = new LeaveRequest("小明", 2, "感冒");LeaveRequest req2 = new LeaveRequest("小红", 5, "家庭事务");LeaveRequest req3 = new LeaveRequest("小刚", 10, "出国旅游");System.out.println("📝 处理请假请求:");teamLeader.handleRequest(req1);System.out.println("---");teamLeader.handleRequest(req2);System.out.println("---");teamLeader.handleRequest(req3);System.out.println("\n💡 说明:请求沿链传递,直到被合适处理器处理。");System.out.println("🔧 可动态调整链结构,如新增总监层。");}
}
实例对应的UML图(简化版)
运行说明:
Approver
定义了处理链的结构和接口。TeamLeader
、DepartmentManager
、GeneralManager
实现具体审批逻辑。- 请求从
teamLeader
开始,根据天数逐级传递。 - 客户端只需将请求交给链首,无需关心处理细节。
四、总结
特性 | 说明 |
---|---|
核心目的 | 解耦请求发送者与接收者,实现请求的动态处理 |
实现机制 | 构建处理器链,请求沿链传递直至被处理 |
优点 | 降低耦合、增强灵活性、支持动态配置、符合开闭原则 |
缺点 | 请求可能未被处理(需设计默认处理)、性能可能下降(链过长)、调试困难 |
适用场景 | 审批流程、事件处理、日志分级、过滤器链、异常处理、权限校验 |
不适用场景 | 处理逻辑简单、必须由特定对象处理、性能敏感且链过长 |
职责链模式使用建议:
- 应确保链中有至少一个处理器能处理请求,避免“黑洞”。
- 可引入“默认处理器”处理未匹配请求。
- 支持运行时动态构建和修改链结构。
- 在 Java 中,Servlet 的
FilterChain
、Spring 的拦截器链是典型应用。
架构师洞见:
职责链模式是“流程可配置化”与“关注点分离”的高级体现。在现代架构中,其思想已演变为中间件管道、事件驱动架构和工作流引擎的核心。例如,在 Web 框架(如 Express、Koa)中,中间件链按顺序处理 HTTP 请求;在微服务中,API 网关的过滤器链执行认证、限流、日志等操作;在工作流引擎(如 Activiti)中,任务节点构成处理链;在前端框架中,事件冒泡机制本质是职责链。未来趋势是:职责链将与低代码流程引擎深度融合,通过可视化拖拽构建处理链;在AI Agent 系统中,Agent 的“决策链”(Reasoning Chain)可视为职责链,每个步骤由不同工具或模型处理;在可观测性系统中,日志、指标、追踪数据将通过职责链进行分级处理与路由。
掌握职责链模式,有助于设计出灵活、可配置、易扩展的业务流程。作为架构师,应在涉及“多级判断”、“顺序处理”或“流程编排”的场景中主动引入职责链。职责链不仅是模式,更是流程治理的哲学——它提醒我们:真正的灵活性,来自于将“决策路径”从硬编码中解放出来,交由配置与链式逻辑动态决定。