Java 设计模式之责任链模式:优雅处理请求的艺术
在软件开发中,我们经常遇到需要多个对象处理同一请求的场景。比如请假审批流程、日志级别处理、异常处理等,这些场景都有一个共同特点:请求需要经过一系列处理步骤,每个步骤可能处理请求,也可能将其传递给下一个步骤。责任链模式(Chain of Responsibility Pattern)正是为这类问题提供了优雅的解决方案。
什么是责任链模式?
责任链模式是一种行为型设计模式,它创建了一个对象链,每个对象都有机会处理请求。请求沿着这条链传递,直到有一个对象处理它为止,或者直到链的末端。
这种模式的核心思想是:解耦请求的发送者和接收者,让多个接收者都有机会处理请求,而发送者不需要知道具体哪个接收者处理了请求。
责任链模式的核心角色
- 抽象处理者(Handler):定义处理请求的接口,包含一个指向 nextHandler 的引用
- 具体处理者(ConcreteHandler):实现抽象处理者接口,判断能否处理请求,如果能则处理,否则将请求传递给下一个处理者
- 请求(Request):需要被处理的对象
责任链模式的实现方式
让我们通过一个实际案例来理解责任链模式。假设我们要实现一个请假审批系统,规则如下:
- 请假 1-3 天:部门主管审批
- 请假 4-7 天:部门经理审批
- 请假 8-30 天:总经理审批
- 请假超过 30 天:不予批准
步骤 1:创建请求类
首先定义一个请假请求类,包含请假人、请假天数等信息:
// 请假请求类
public class LeaveRequest {
private String employeeName; // 员工姓名
private int leaveDays; // 请假天数
public LeaveRequest(String employeeName, int leaveDays) {
this.employeeName = employeeName;
this.leaveDays = leaveDays;
}
// getter方法
public String getEmployeeName() {
return employeeName;
}
public int getLeaveDays() {
return leaveDays;
}
}
步骤 2:创建抽象处理者
定义一个审批者抽象类,作为所有具体审批者的父类:
// 抽象审批者
public abstract class Approver {
// 下一个审批者
protected Approver nextApprover;
// 设置下一个审批者
public void setNextApprover(Approver nextApprover) {
this.nextApprover = nextApprover;
}
// 处理请假请求的抽象方法
public abstract void processRequest(LeaveRequest request);
}
步骤 3:创建具体处理者
分别实现部门主管、部门经理和总经理这三个具体处理者:
// 部门主管
public class Director extends Approver {
@Override
public void processRequest(LeaveRequest request) {
// 处理1-3天的请假
if (request.getLeaveDays() >= 1 && request.getLeaveDays() <= 3) {
System.out.println(
"部门主管批准 " + request.getEmployeeName() +
" 请假 " + request.getLeaveDays() + " 天"
);
}
// 超过3天则交给下一个审批者
else if (nextApprover != null) {
nextApprover.processRequest(request);
}
}
}
// 部门经理
public class Manager extends Approver {
@Override
public void processRequest(LeaveRequest request) {
// 处理4-7天的请假
if (request.getLeaveDays() >= 4 && request.getLeaveDays() <= 7) {
System.out.println(
"部门经理批准 " + request.getEmployeeName() +
" 请假 " + request.getLeaveDays() + " 天"
);
}
// 超过7天则交给下一个审批者
else if (nextApprover != null) {
nextApprover.processRequest(request);
}
}
}
// 总经理
public class GeneralManager extends Approver {
@Override
public void processRequest(LeaveRequest request) {
// 处理8-30天的请假
if (request.getLeaveDays() >= 8 && request.getLeaveDays() <= 30) {
System.out.println(
"总经理批准 " + request.getEmployeeName() +
" 请假 " + request.getLeaveDays() + " 天"
);
}
// 超过30天则不予批准
else {
System.out.println(
request.getEmployeeName() + " 请假 " + request.getLeaveDays() +
" 天,超过最大允许天数,不予批准"
);
}
}
}
步骤 4:客户端使用
创建责任链并测试不同的请假请求:
public class Client {
public static void main(String[] args) {
// 创建各个审批者
Approver director = new Director();
Approver manager = new Manager();
Approver generalManager = new GeneralManager();
// 构建责任链:部门主管 -> 部门经理 -> 总经理
director.setNextApprover(manager);
manager.setNextApprover(generalManager);
// 创建不同的请假请求
LeaveRequest request1 = new LeaveRequest("张三", 2);
LeaveRequest request2 = new LeaveRequest("李四", 5);
LeaveRequest request3 = new LeaveRequest("王五", 15);
LeaveRequest request4 = new LeaveRequest("赵六", 35);
// 处理请求
director.processRequest(request1);
director.processRequest(request2);
director.processRequest(request3);
director.processRequest(request4);
}
}
运行结果:
部门主管批准 张三 请假 2 天
部门经理批准 李四 请假 5 天
总经理批准 王五 请假 15 天
赵六 请假 35 天,超过最大允许天数,不予批准
责任链模式的变种
除了上述线性责任链,还有其他几种常见的责任链形式:
- 环形责任链:最后一个处理者指向第一个处理者
- 树形责任链:一个处理者可以有多个后继者
- 带条件的责任链:根据条件决定下一个处理者
责任链模式的优缺点
优点
- 降低耦合度:请求的发送者和接收者解耦
- 灵活性高:可以灵活地改变链的结构和顺序
- 符合开闭原则:新增处理者不需要修改原有代码
- 简化对象:每个对象只需关注自己的职责范围
缺点
- 请求可能不被处理:如果链中没有对象处理请求,请求可能会被丢弃
- 调试复杂:请求的处理路径可能较长,调试时需要跟踪整个链
- 性能影响:对于长链,可能会有一定的性能开销
责任链模式的应用场景
- 审批流程:如请假、报销、采购等多级审批
- 日志系统:不同级别日志由不同处理器处理
- 过滤器 / 拦截器:如 Web 中的过滤器链、Spring 的拦截器链
- 异常处理:多层异常捕获处理
- 事件冒泡:如 GUI 中的事件传递机制
Java 中的责任链模式实例
在 Java 标准库和主流框架中,责任链模式有很多应用:
- Servlet Filter:所有 Filter 组成一个链,依次处理请求
- Spring Interceptor:拦截器链对请求进行预处理和后处理
- Netty ChannelPipeline:处理网络事件的责任链
- Java 异常处理:try-catch 块的嵌套本质上也是一种责任链
总结
责任链模式通过构建处理者对象链,让请求在链中传递直至被处理,有效解耦了请求发送者和接收者。它特别适合处理那些需要多级处理或动态调整处理流程的场景。
在实际开发中,使用责任链模式时需要注意:
- 避免构建过长的责任链,以免影响性能
- 确保每个请求都能被适当处理,避免无人处理的情况
- 合理设计处理者的职责边界,保持单一职责原则
掌握责任链模式,能让我们的代码更加灵活、可扩展,更好地应对复杂业务场景的变化。