责任链设计模式(Chain of Responsibility Pattern)
1. 什么是责任链模式?
责任链模式是一种行为型设计模式。
核心思想:
将多个处理节点按照顺序组织成一条链,请求依次经过每个节点,由每个节点决定是否继续向下执行。
简单理解:
一个任务需要经过多个环节:
请求
↓
节点1
↓
节点2
↓
节点3
↓
完成
每个节点:
- 处理自己的业务
- 修改上下文数据
- 决定是否继续执行
例如请假流程:
员工提交请假
↓
MT审批
↓
LD审批
↓
大LD审批
↓
最终结果
每个人都是责任链上的一个节点。
2. 为什么需要责任链模式?
2.1 没有责任链的问题
假设请假流程:
实习生请假:
需要:
MT同意
↓
LD同意
↓
大LD同意
代码可能:
public boolean requestLeave(User user){
if(!mtApprove(user)){
return false;
}
if(!ldApprove(user)){
return false;
}
if(!ldldApprove(user)){
return false;
}
return true;
}
刚开始没问题。
但是流程变化:
新增:
HR审批
部门负责人审批
老板审批
代码:
if(){
}
if(){
}
if(){
}
if(){
}
if(){
}
问题:
- 流程代码越来越长
- 每新增一个节点都需要修改原代码
- 节点之间耦合严重
3. 责任链模式解决什么问题?
责任链模式将:
流程控制
业务节点
拆开。
结构:
ProcessController
|
↓
------------------------------------------------
MT审批 LD审批 大LD审批 HR审批
流程控制器负责:
按照顺序执行节点
每个节点负责:
自己的业务逻辑
4. 责任链核心组成
责任链通常包含四个部分:
① 上下文 Context
负责保存链路中的数据。
例如:
请假流程:
User user
审批结果:
needBreak
代码:
public class ProcessContext<T extends ProcessModel>{
// 责任链标识
private String code;
// 业务数据
private T processModel;
// 是否终止链路
private Boolean needBreak = false;
}
为什么需要 Context?
因为责任链中的每个节点需要共享数据。
例如:
MT节点
修改审批状态
↓
LD节点
读取审批状态
继续处理
② 统一流程接口
所有节点实现:
public interface BusinessProcess<T extends ProcessModel>{
void process(ProcessContext<T> context);
}
作用:
保证所有节点:
输入一致
执行方式一致
③ 业务节点
例如:
审批节点:
public abstract class Authority
implements BusinessProcess<User>{
protected boolean requestLeave(User user)
throws Exception{
throw new Exception(
"没有权限"
);
}
@Override
public void process(
ProcessContext<User> context
){
try{
boolean result =
requestLeave(
context.getProcessModel()
);
// 是否继续执行
context.setNeedBreak(!result);
}catch(Exception e){
context.setNeedBreak(true);
}
}
}
父类负责:
统一流程
子类负责:
具体审批逻辑
MT节点
public class MT extends Authority{
@Override
protected boolean requestLeave(User user){
System.out.println(
"MT同意请假"
);
return true;
}
}
LD节点
public class LD extends Authority{
@Override
protected boolean requestLeave(User user){
System.out.println(
"LD同意请假"
);
return true;
}
}
大LD节点
public class LDLD extends Authority{
@Override
protected boolean requestLeave(User user){
System.out.println(
"大LD同意请假"
);
return true;
}
}
5. 责任链执行器
责任链核心:
负责:
- 保存节点
- 按顺序执行
- 判断是否中断
public class ProcessController {
private List<BusinessProcess> processList;
public ProcessContext process(
ProcessContext context
){
for(
BusinessProcess process:
processList
){
process.process(context);
// 是否终止
if(context.getNeedBreak()){
break;
}
}
return context;
}
}
6. 使用责任链
public class Main {
public static void main(String[] args){
User user =
new User("xhy");
ProcessContext<User> context =
new ProcessContext<>();
context.setProcessModel(user);
ProcessController controller =
new ProcessController();
controller.setProcessList(
Arrays.asList(
new MT(),
new LD(),
new LDLD()
)
);
controller.process(context);
if(context.getNeedBreak()){
System.out.println(
"请假失败"
);
return;
}
System.out.println(
"请假成功"
);
}
}
执行:
MT同意请假
LD同意请假
大LD同意请假
请假成功
7. 责任链模式和模板模式区别
很多人第一次看责任链会疑惑:
不就是多个任务按顺序执行吗?模板模式也可以。
确实类似。
但是两者解决的问题不同。
模板模式
核心:
固定流程,部分步骤交给子类实现。
结构:
父类
固定流程
|
↓
子类实现步骤
例如:
文件上传:
上传流程:
1. 校验文件
2. 上传
3. 记录日志
不同存储:
上传本地
上传OSS
上传服务器
流程固定。
责任链模式
核心:
多个节点组成流程,每个节点可以决定是否继续。
结构:
节点1
↓
节点2
↓
节点3
↓
节点4
特点:
- 节点数量可变化
- 节点顺序可调整
- 节点可以中断
- 节点可以动态增加
例如:
审批流程:
员工
↓
主管
↓
经理
↓
总监
8. 两者核心区别
| 模板模式 | 责任链模式 | |
|---|---|---|
| 关注点 | 流程固定 | 任务编排 |
| 控制者 | 父类 | 链路控制器 |
| 节点关系 | 继承关系 | 组合关系 |
| 流程变化 | 较少变化 | 动态变化 |
| 是否可以中断 | 通常不能 | 可以 |
| 是否动态添加节点 | 困难 | 容易 |
| 适合 | 固定流程 | 审批/过滤/处理链 |
简单理解:
模板模式:
我规定流程,你实现步骤。
责任链:
我有很多处理节点,谁处理由链路决定。
9. 责任链模式什么时候使用?
判断标准:
条件1:一个请求需要经过多个处理阶段
例如:
订单创建:
参数校验
↓
库存检查
↓
价格计算
↓
优惠计算
↓
订单生成
适合责任链。
条件2:处理节点可能动态变化
例如:
风控:
黑名单检查
↓
风险评分
↓
人工审核
↓
短信验证
不同业务:
可能:
增加节点
删除节点
调整顺序
适合责任链。
条件3:某个节点可以终止流程
例如:
权限校验:
登录检查
↓
权限检查
↓
业务执行
如果:
没有权限:
直接结束。
10. 常见应用场景
① Spring MVC HandlerInterceptor
Spring MVC 拦截器本质就是责任链。
请求流程:
HTTP请求
↓
登录拦截器
↓
权限拦截器
↓
日志拦截器
↓
Controller
每个拦截器:
可以:
- 执行前置逻辑
- 执行后置逻辑
- 中断请求
例如:
preHandle(){
return false;
}
直接终止后续流程。
② Tomcat Filter
过滤器链:
Request
↓
EncodingFilter
↓
AuthFilter
↓
LogFilter
↓
Servlet
每个 Filter:
可以:
chain.doFilter()
继续执行。
也可以:
直接返回。
③ RPC 框架
RPC 请求:
请求
↓
参数校验
↓
限流
↓
负载均衡
↓
序列化
↓
发送请求
↓
日志记录
每一步:
都是责任链节点。
④ 任务编排系统
例如:
订单流程:
创建订单
↓
扣库存
↓
扣余额
↓
发送通知
↓
完成订单
每个任务:
一个节点。
11. 责任链 + 模板模式
实际项目中经常一起使用。
例如:
责任链负责:
节点顺序
节点组合
流程控制
模板负责:
单个节点内部固定流程
例如:
订单审核:
责任链:
风险审核
↓
库存审核
↓
金额审核
每个审核节点内部:
模板:
参数校验
↓
业务处理
↓
记录结果
组合:
责任链控制大流程
模板控制单节点流程
12. 总结
责任链模式核心:
将多个有状态处理节点按照顺序组合,请求依次经过节点,每个节点处理自己的逻辑,并决定是否继续执行。
解决:
- 大量流程判断
- 多阶段处理
- 动态流程编排
- 可中断业务流程
适合:
- 审批流程
- Spring MVC拦截器
- Tomcat Filter
- RPC调用链
- 风控流程
- 任务编排
一句话总结:
责任链模式就是把复杂流程拆成多个独立节点,通过链路组合完成任务编排,让每个节点只关注自己的职责。
在中间件和框架源码中,经常看到:
工厂负责创建节点
责任链负责组织流程
模板负责节点内部执行
这三个设计模式组合起来,是很多组件化系统的核心设计方式。