责任链模式:让每个对象都有机会处理请求
责任链模式,说白了就是一条处理流水线。每个节点只关心自己能不能处理,处理不了就往后传。我刚开始接触这个模式时,觉得它跟if-else链没啥区别,直到在项目中遇到一个审批流程,才真正体会到它的妙处。
什么是责任链模式?
先看一个生活中的例子。你请假3天,组长批了就行。请假7天,组长批完还得经理批。请假15天,那得总监也过目。每个审批人只负责自己权限内的部分,超出范围就往上抛。这就是责任链的雏形。
在软件世界里,责任链模式的定义是:将请求的发送者和接收者解耦,让多个对象都有机会处理这个请求。这些对象串成一条链,请求沿着链传递,直到被处理为止。
核心结构
责任链模式的结构其实很简单,就三个角色:
- Handler(抽象处理者):定义处理请求的接口,同时维护下一个处理者的引用
- ConcreteHandler(具体处理者):实现自己的处理逻辑,决定是处理还是转发
- Client(客户端):组装链并发送请求
我画了一张图,帮你直观理解这个结构:
代码实现
光说不练假把式。咱们直接看代码,我以请假审批为例:
// 抽象处理者
public abstract class Approver {
protected Approver nextApprover;
protected String name;
public Approver(String name) {
this.name = name;
}
public void setNextApprover(Approver next) {
this.nextApprover = next;
}
// 模板方法:定义处理流程
public void handleRequest(int days) {
if (canApprove(days)) {
doApprove(days);
} else if (nextApprover != null) {
nextApprover.handleRequest(days);
} else {
System.out.println("无人能审批,拒绝!");
}
}
protected abstract boolean canApprove(int days);
protected abstract void doApprove(int days);
}
// 具体处理者:组长
public class TeamLeader extends Approver {
public TeamLeader(String name) {
super(name);
}
@Override
protected boolean canApprove(int days) {
return days <= 3;
}
@Override
protected void doApprove(int days) {
System.out.println(name + "(组长)审批了" + days + "天假期");
}
}
// 具体处理者:经理
public class Manager extends Approver {
public Manager(String name) {
super(name);
}
@Override
protected boolean canApprove(int days) {
return days <= 7;
}
@Override
protected void doApprove(int days) {
System.out.println(name + "(经理)审批了" + days + "天假期");
}
}
// 具体处理者:总监
public class Director extends Approver {
public Director(String name) {
super(name);
}
@Override
protected boolean canApprove(int days) {
return days <= 15;
}
@Override
protected void doApprove(int days) {
System.out.println(name + "(总监)审批了" + days + "天假期");
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
// 组装责任链
Approver teamLeader = new TeamLeader("张三");
Approver manager = new Manager("李四");
Approver director = new Director("王五");
teamLeader.setNextApprover(manager);
manager.setNextApprover(director);
// 发送请求
teamLeader.handleRequest(2); // 组长审批
teamLeader.handleRequest(5); // 经理审批
teamLeader.handleRequest(10); // 总监审批
teamLeader.handleRequest(20); // 无人能审批
}
}
优缺点分析
| 优点 | 缺点 |
|---|---|
|
|
应用场景
责任链模式在哪些地方用得最多?我总结了几类:
- 审批流程:请假、报销、采购等需要逐级审批的业务
- 过滤器/拦截器:Java Servlet中的Filter链、Spring的Interceptor链
- 日志框架:Log4j、Logback中的Logger链,日志级别不够就往上抛
- 异常处理:try-catch块本身就是一种责任链,catch按顺序匹配
- 事件处理:GUI中的事件冒泡机制,从子组件传到父组件
你想想看,这些场景是不是都有一个共同点?处理者之间有明确的优先级或层级关系,而且每个处理者只关心自己能力范围内的事。
与if-else的区别
有人会问:用if-else也能实现类似效果,为啥非要用责任链?
嗯,这个问题问得好。我举个例子你就明白了:
// if-else方式
public void handle(int days) {
if (days <= 3) {
// 组长处理
} else if (days <= 7) {
// 经理处理
} else if (days <= 15) {
// 总监处理
} else {
// 拒绝
}
}
这段代码有什么问题?所有处理逻辑耦合在一起。哪天要加个副总裁审批,你得改这个if-else块。哪天要调整审批顺序,你还得改。说白了,if-else是硬编码,责任链是动态组合。
核心区别一句话:if-else是编译时确定的,责任链是运行时动态的。如果你的处理逻辑经常变化,或者需要灵活组合,那就用责任链。如果逻辑固定不变,if-else更简单直接。
实际项目中的变体
我在项目中见过两种责任链的变体,挺有意思:
- 纯责任链:请求必须被某个处理者处理,否则抛异常。适合审批流程。
- 不纯责任链:请求可以被多个处理者处理,每个处理者处理完一部分,继续往下传。适合过滤器链。
举个例子,日志框架就是典型的不纯责任链。一条日志消息,可能同时被控制台、文件、远程服务器三个处理者处理。每个处理者处理完,不阻断,继续往下传。
我个人更常用不纯责任链,因为它更灵活。但要注意,不纯责任链容易导致重复处理,需要设计好终止条件。
总结
责任链模式,说白了就是把一堆处理者串起来,让请求自己找路。它的精髓在于解耦——发送者不用关心谁处理,处理者不用关心谁来发。
记住几个要点:
- 链的组装要灵活,最好能配置化
- 链不要太长,5层以内为宜
- 链尾一定要有兜底处理,避免请求丢失
- 调试时可以在每个处理者加日志,方便追踪
好了,责任链模式就讲到这里。下一章咱们聊聊另一种行为型模式——命令模式,看看怎么把请求封装成对象。