1. 责任链模式的定义
责任链模式(Chain of Responsibility Pattern) 是一种行为型设计模式,它的核心思想是: 将请求的发送者与处理者解耦,使多个对象都有机会处理请求,并将请求沿链传递,直到被处理。
- 解耦请求发送者与处理,发送者可以不需要关心谁最终处理请求。
- 支持动态组合和顺序变更。
- 链上的节点可以自由决定是否处理请求。每个处理者可以决定:自己处理或传给下一个。
2. 责任链模式的几种模型:
2.1 代码结构层面分类
2.1.1 链表式结构
去中心化,简单的业务链,或者节点之间有强顺序依赖。
[Client]
|
v
+-----------+ +-----------+ +-----------+
| Handler A | -----> | Handler B | -----> | Handler C | -----> null
+-----------+ +-----------+ +-----------+
| next: B | | next: C | | next: null|
+-----------+ +-----------+ +-----------+
2.1.2 集中管理器结构
Chain 管理器中心化管理,节点间解耦,容易动态排序、插入、删除。
[Client]
|
v
+-----------------------------+
| Chain Manager | (持有 List<Handler>)
| --------------------------- |
| index = 0 |
| |
| 1. [Handler A] <---------+ | (Manager 循环调用或递归调用)
| 2. [Handler B] <---------+ |
| 3. [Handler C] <---------+ |
+-----------------------------+
2.2 业务逻辑层面分类
2.2.1 短路型
短路型 (Short-circuit),链上任何一个节点处理完请求后,直接中断,不再向下传递。适用于“权限校验”、“参数验证”等场景,一旦发现问题就无需继续。
Request
|
v
+----------------+ NO
| 1. AuthCheck | ----------------> [ 拒绝/报错 ]
+----------------+
| YES (继续)
v
+----------------+ NO
| 2. ParamCheck | ----------------> [ 拒绝/报错 ]
+----------------+
| YES (继续)
v
+----------------+
| 3. Business | (只有前两关都过,才能到这)
+----------------+
2.2.1 贯穿型
贯穿型 (Pass-through):链上所有节点都会处理请求,每个节点处理完后都会传递给下一个。适用于“日志记录”、“性能监控”、“数据审计”等需要多重处理的场景。
Request
|
v
+----------------+
| 1. LogHandler | (记录:"请求进来了")
+----------------+
|
v
+----------------+
| 2. FormatHdlr | (动作:把参数去空格、大写化)
+----------------+
|
v
+----------------+
| 3. AuditHdlr | (记录:"数据被修改了")
+----------------+
|
v
[最终处理]
3. 责任链模式代码举例
Client
|
Handler (抽象)
|
ConcreteHandler1 --> ConcreteHandler2 --> ConcreteHandler3 ...
3.1 Handler 抽象处理者
public abstract class Handler {
protected Handler next;
public Handler setNext(Handler next) {
this.next = next;
return next;
}
public final void handle(RequestContext ctx) {
if (onHandle(ctx)) {
return;
}
if (next != null) {
next.handle(ctx);
}
}
protected abstract boolean onHandle(RequestContext ctx);
}
3.2 ConcreteHandler 具体处理者
public class AuthHandler extends Handler {
@Override
protected boolean onHandle(RequestContext ctx) {
String token = (String) ctx.get("token");
if (token == null || token.isEmpty()) {
throw new RuntimeException("unauthorized");
}
return false;
}
}
public class ParamValidateHandler extends Handler {
@Override
protected boolean onHandle(RequestContext ctx) {
Object uid = ctx.get("userId");
if (uid == null) {
throw new IllegalArgumentException("userId required");
}
return false;
}
}
public class BizHandler extends Handler {
@Override
protected boolean onHandle(RequestContext ctx) {
System.out.println("do real business");
return true;
}
}
3.3 Client 客户端
// 客户端调用
public class Client {
public static void main(String[] args) {
RequestContext ctx = new RequestContext();
ctx.put("token", "abc");
ctx.put("userId", 123);
Handler head = new AuthHandler();
head.setNext(new ParamValidateHandler())
.setNext(new BizHandler());
head.handle(ctx);
}
}
public class RequestContext {
private final Map<String, Object> attrs = new HashMap<>();
public void put(String key, Object value) {
attrs.put(key, value);
}
public Object get(String key) {
return attrs.get(key);
}
}
4. 责任链模式的设计思想
-
解耦请求发送者与处理者。
-
单一职责:节点只处理自身逻辑。
-
递归/循环链式传递,体现动态和灵活。
-
开闭原则:新增节点无需改动原有链。
-
可扩展性:适合多种复杂业务场景。
5. 一些问题
Q1: 责任链模式与装饰器模式的区别是什么?
A1:
- 责任链模式:多个处理器按顺序尝试处理同一个请求,直到有一个处理器能够处理为止(或全部处理完)
- 装饰器模式:对同一个对象进行层层包装,每层都增加新的功能
- 核心区别:责任链强调"选择性处理",装饰器强调"功能叠加"
// 责任链:只有一个处理器会处理请求
handler1.handle(request) -> handler2.handle(request) -> handler3.handle(request)
// 装饰器:每层都会处理,功能叠加
decorator1(decorator2(decorator3(core)))
Q2: 责任链模式在什么场景下不适用?
-
处理逻辑简单且固定
- 解释:如果处理步骤始终固定且不需要动态调整,那么直接用顺序调用或 if-else 就足够。
- 例子:一个请求只需要固定地经过 A→B→C 三个处理器,且不会变更。此时用责任链反而显得多余、复杂。
-
性能要求极高
- 解释:责任链需要依次遍历处理器,每次调用都涉及方法分发甚至对象查找,存在额外开销。
- 例子:在 Android Framework 的核心渲染或输入事件分发等高频调用场景,如果链很长,会产生明显性能损耗。
-
处理器之间有强依赖关系
- 解释:责任链强调 解耦(各处理器独立,不关心前后顺序细节)。但如果处理器必须依赖上一步的具体实现,责任链就不合适。
- 例子:步骤 B 必须依赖步骤 A 的内部状态或返回值,而不仅仅是一个统一的上下文参数,这种强依赖违背了解耦设计。
-
需要回滚操作
- 解释:责任链是单向流转,请求被传递下去后通常不追溯处理历史。如果业务需要类似事务的回滚(所有步骤要么全部成功,要么全部撤销),责任链难以实现。
- 例子:在数据库批处理或支付流程中,某个处理失败时需要撤销之前已完成的步骤;责任链无法天然支持,需要额外补偿机制。