1. 责任链模式的定义
责任链模式(Chain of Responsibility Pattern) 是一种行为型设计模式,它的核心思想是: 将请求的发送者与处理者解耦,使多个对象都有机会处理请求,并将请求沿链传递,直到被处理。
- 解耦请求发送者与处理,发送者不知道谁最终处理请求。
- 支持动态组合和顺序变更。
- 链上的节点可以自由决定是否处理请求。每个处理者可以决定:自己处理或传给下一个。
两类模型:
- 短路型 (Short-circuit) :链上任何一个节点处理完请求后,直接中断,不再向下传递。适用于"权限校验"、"参数验证"等场景,一旦发现问题就无需继续。
- 贯穿型 (Pass-through) :链上所有节点都会处理请求,每个节点处理完后都会传递给下一个。适用于"日志记录"、"性能监控"、"数据审计"等需要多重处理的场景。
2. 责任链模式的结构
责任链模式主要包含以下角色:
- Handler(抽象处理者): 定义处理请求的接口,并持有对下一个处理者的引用。
- ConcreteHandler(具体处理者):实现抽象处理者接口,决定是否处理请求或将请求传递。
- Client(客户端):发送请求,不关心具体由谁处理。
txt
Client
|
Handler (抽象)
|
ConcreteHandler1 --> ConcreteHandler2 --> ConcreteHandler3 ...
特点:
- 链可以是单向的,也可以是动态构建的。
- 节点顺序决定请求处理的优先级。
- 可以使用递归或循环遍历链。
2.1 Handler 抽象处理者
java
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);
}
2.2 ConcreteHandler 具体处理者
java
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;
}
}
2.3 Client 客户端
java
// 客户端调用
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);
}
}
3. 责任链模式的优缺点
优点 :
- 降低耦合:发送者不关心谁处理请求。
- 增强灵活性:链可动态增加、删除节点。
- 符合开闭原则:新增节点无需修改现有代码。
- 职责单一:每个节点只负责自身处理逻辑。
缺点 :
- 链过长可能影响性能。
- 请求可能无人处理,需要合理设计默认处理策略。
- 调试难度:链式调用和递归可能难以追踪。
- 节点顺序敏感:链条顺序不当可能导致逻辑错误。
4. 责任链模式的设计思想
-
解耦请求发送者与处理者。
-
单一职责:节点只处理自身逻辑。
-
递归/循环链式传递,体现动态和灵活。
-
开闭原则:新增节点无需改动原有链。
-
可扩展性:适合多种复杂业务场景。
5. 一些问题
Q1: 责任链模式与装饰器模式的区别是什么?
A1:
- 责任链模式:多个处理器按顺序尝试处理同一个请求,直到有一个处理器能够处理为止(或全部处理完)
- 装饰器模式:对同一个对象进行层层包装,每层都增加新的功能
- 核心区别:责任链强调"选择性处理",装饰器强调"功能叠加"
java
// 责任链:只有一个处理器会处理请求
handler1.handle(request) -> handler2.handle(request) -> handler3.handle(request)
// 装饰器:每层都会处理,功能叠加
decorator1(decorator2(decorator3(core)))
Q2: 责任链模式在什么场景下不适用?
-
处理逻辑简单且固定
- 解释:如果处理步骤始终固定且不需要动态调整,那么直接用顺序调用或 if-else 就足够。
- 例子:一个请求只需要固定地经过 A→B→C 三个处理器,且不会变更。此时用责任链反而显得多余、复杂。
-
性能要求极高
- 解释:责任链需要依次遍历处理器,每次调用都涉及方法分发甚至对象查找,存在额外开销。
- 例子:在 Android Framework 的核心渲染或输入事件分发等高频调用场景,如果链很长,会产生明显性能损耗。
-
处理器之间有强依赖关系
- 解释 :责任链强调 解耦(各处理器独立,不关心前后顺序细节)。但如果处理器必须依赖上一步的具体实现,责任链就不合适。
- 例子:步骤 B 必须依赖步骤 A 的内部状态或返回值,而不仅仅是一个统一的上下文参数,这种强依赖违背了解耦设计。
-
需要回滚操作
- 解释:责任链是单向流转,请求被传递下去后通常不追溯处理历史。如果业务需要类似事务的回滚(所有步骤要么全部成功,要么全部撤销),责任链难以实现。
- 例子:在数据库批处理或支付流程中,某个处理失败时需要撤销之前已完成的步骤;责任链无法天然支持,需要额外补偿机制。