这是 2020 年 8 月整理的设计模式专题第十三篇。责任链模式是”审批流”的抽象——请求像走流程一样在一条链上逐级传递,每个节点决定自己处理还是传给下一个。Servlet 的 FilterChain 是它的经典应用。
简单说明
责任链模式(Chain of Responsibility Pattern):为请求创建一个接受此请求对象的链。
- 适用于一个请求的处理需要多个对象中的一个或者多个协作处理;
- 使得请求的发送者和接收者(处理者)解耦;
- 可以动态的组合处理者;
- 缺点:责任链太长或者处理时间长会影响性能。
客户端 ──> 处理者1 ──> 处理者2 ──> 处理者3 ──> (结束)
│ │ │
能处理? 不能→下传 不能→下传
能→处理完 能→处理完 能→处理完
代码实现
模拟发布一个课程,需要多级审批:
/**
* 描述:模拟发布一个课程
*/
@Data
@AllArgsConstructor
public class Course {
private String courseName;
private String video;
private String article;
}
/**
* 描述:审批人抽象类
*/
public abstract class Approver {
protected Approver nextApprover;
protected void setNextApprover(Approver nextApprover) {
this.nextApprover = nextApprover;
}
public abstract void approve(Course course);
}
/**
* 描述:视频审核人
*/
public class VideoApprover extends Approver {
@Override
public void approve(Course course) {
if (null == course || null == course.getVideo()) {
System.out.println("video审核失败");
return;
}
System.out.println("video审核成功");
// 处理完,传给下一个处理者
if (null != nextApprover) {
nextApprover.approve(course);
}
}
}
/**
* 描述:手记审核人
*/
public class ArticleApprover extends Approver {
@Override
public void approve(Course course) {
if (null == course || null == course.getArticle()) {
System.out.println("article审核失败");
return;
}
System.out.println("article审核成功");
if (null != nextApprover) {
nextApprover.approve(course);
}
}
}
public class Test {
public static void main(String[] args) {
Approver videoApprover = new VideoApprover();
Approver articleApprover = new ArticleApprover();
// 动态组合:视频审核 → 手记审核
videoApprover.setNextApprover(articleApprover);
Course course = new Course("Java架构师", "video.mp4", "article.md");
videoApprover.approve(course);
}
}
链式结构:
- 抽象处理者(Approver):持有
nextApprover引用,定义处理接口; - 具体处理者(VideoApprover / ArticleApprover):判断自己能否处理,能则处理并下传,不能则直接下传;
- 组装链:
videoApprover.setNextApprover(articleApprover)—— 处理者通过持有”下一个”指针形成链,客户端只调用链头。
动态组合:链的顺序和成员完全由组装代码决定。今天要”视频→手记”,明天要”手记→视频”或加一个”整体审核人”,改组装代码即可,处理者类本身不动。
责任链的价值
| 对比项 | 硬编码 if-else 审批 | 责任链模式 |
|---|---|---|
| 发送者与处理者 | 发送者要认识所有处理者 | 发送者只认识链头 |
| 组合方式 | 写死在代码里 | 运行时动态组装 |
| 新增处理者 | 改业务代码 | 加一个处理者类 + 组装 |
| 职责 | 集中在发送者 | 分散到每个处理者 |
链的两种流转方式:
- 逐个传递(本例):每个处理者都参与,处理完传给下一个(如过滤器);
- 短路处理:第一个能处理的人处理完就结束(如请假审批,组长能批就不往上报)。
适用场景与优缺点
适用场景:
- 一个请求需要多个对象中的一个或多个协作处理;
- 处理者集合不确定、需要动态组合;
- 想实现请求的发送者与接收者解耦(如过滤器链、拦截器链)。
优点:
- 请求发送者与处理者解耦;
- 处理者可以动态组合,灵活调整;
- 符合单一职责原则:每个处理者只做一件事。
缺点:
- 责任链太长或处理时间长会影响性能;
- 不容易定位问题:请求在链上流转,出错时难以确认是哪一环;
- 可能出现请求”无人处理”的情况(链断了)。
现实中的应用
| 场景 | 说明 |
|---|---|
| javax.servlet.FilterChain | 过滤器链逐级处理请求 |
| Spring MVC 拦截器 | HandlerInterceptor 链 |
| MyBatis 插件 | 拦截器层层处理 SQL |
| Netty Pipeline | ChannelHandler 责任链处理 IO 事件 |
| 审批流 | 请假/报销/发布的多级审批 |
小结
- 责任链模式为请求创建处理者链,请求在链上逐级传递,发送者与处理者解耦。
- 实现:抽象处理者持有
nextApprover指针,具体处理者”能处理就处理,不能就下传”,客户端只调链头。 - 可动态组合处理者,符合单一职责原则。
- 代价:链太长影响性能、问题定位难。
- 一句话:层层审批,各管一段——处理不了的往下传。