Java设计模式之职责链模式详解
Java设计模式之职责链模式详解
一、职责链模式核心思想
核心目标:将请求的发送者与接收者解耦,使多个对象都有机会处理请求。这些处理者形成链式结构,请求沿链传递直到被处理或到达链尾,如政府审批层层上报机制。
二、职责链模式类图(Mermaid)
三、代码实现示例
1. 请假审批场景
// 抽象处理者
abstract class Approver {protected Approver nextApprover;protected String name;protected int maxApproveDays;public Approver(String name, int maxDays) {this.name = name;this.maxApproveDays = maxDays;}public Approver setNext(Approver next) {this.nextApprover = next;return this;}public void processRequest(LeaveRequest request) {if (request.getDays() <= maxApproveDays) {System.out.printf("%s 审批了 %d 天请假(原因:%s)\n", name, request.getDays(), request.getReason());} else if (nextApprover != null) {nextApprover.processRequest(request);} else {System.out.println("请假天数过长,无人可审批!");}}
}// 具体处理者
class Manager extends Approver {public Manager() { super("张经理", 3); }
}class Director extends Approver {public Director() { super("王总监", 7); }
}class CEO extends Approver {public CEO() { super("李总裁", 15); }
}// 请求对象
class LeaveRequest {private int days;private String reason;// 构造方法、getter省略
}// 客户端调用
Approver chain = new Manager().setNext(new Director()).setNext(new CEO());chain.processRequest(new LeaveRequest(5, "看病"));
// 输出:王总监 审批了 5 天请假(原因:看病)
chain.processRequest(new LeaveRequest(20, "旅游"));
// 输出:请假天数过长,无人可审批!
四、模式优缺点分析
✅ 优势
- 解耦请求与处理:发送者无需知道具体处理者
- 动态调整责任链:可运行时修改链结构
- 符合开闭原则:新增处理者无需修改已有代码
❌ 缺点
- 请求可能未被处理:需要设计默认处理逻辑
- 性能影响:长链可能导致请求处理延迟
- 调试困难:请求传递路径不易追踪
五、典型应用场景
- 多级审批系统:OA系统中的请假/报销审批
- 异常处理机制:Spring MVC的异常处理链
- 过滤器/拦截器链:Servlet Filter、Spring Interceptor
- 日志处理系统:不同级别日志(DEBUG/INFO/ERROR)分发
- 游戏事件处理:UI元素的事件冒泡机制
六、Mermaid序列图(请求传递流程)
七、职责链模式 vs 其他模式
对比模式 | 核心区别 |
---|---|
装饰器模式 | 层层增强功能,所有处理者必须执行 |
命令模式 | 封装请求为对象,关注请求生命周期 |
状态模式 | 状态转换改变行为,处理者内部切换 |
八、高级应用技巧
1. 组合模式实现树形责任链
2. 中断链式传递
public void processRequest(Request req) {if (canHandle(req)) {// 处理逻辑return; // 中断传递}if (next != null) next.processRequest(req);
}
九、Spring框架应用案例
Spring Security过滤器链
十、常见问题解答
Q1:如何避免循环链?
- 设置最大传递深度:计数器限制链长度
- 使用DAG验证:构建链时检查环状结构
- 单元测试覆盖:验证链式调用路径
Q2:如何处理异步责任链?
- 使用CompletableFuture:Java 8+的异步编程
public CompletableFuture<Void> asyncProcess(Request req) {return CompletableFuture.runAsync(() -> process(req));
}
Q3:如何调试责任链?
- 添加Trace ID:为请求添加唯一标识
- 日志记录器:每个处理者记录处理状态
public void process(Request req) {log.debug("Handler {} 开始处理请求 {}", name, req.getId());// 处理逻辑
}