责任链模式
责任链模式可以在系统中建立一个链,这样消息可以在首先接收到它的级别被处理,或者可以定位到可以处理它的对象。

责任链模式(Chain of Responsibility Pattern)包含以下主要角色:
抽象处理者(CommandHandler)
定义了一个处理请求的接口,通常会包含一个处理请求的方法(如 handleRequest()),以及持有下一个处理者的引用。抽象处理者一般被设计为抽象类或接口。具体处理者(ConcreteHandler)
继承自抽象处理者,实现了处理请求的方法。在实现时,具体处理者可以根据请求内容决定是自己处理还是将请求传递给下一个处理者。如果有能力处理请求,则进行处理;否则,调用其持有的下一个处理者的处理方法。请求(Request)
表示需要被处理的实体对象,它包含了所有必要的信息以供处理者做出是否处理该请求的决策。客户端(Client)
负责构造责任链,并向链头的处理者提交请求。客户端并不关心请求如何在链中被传递和处理,它只需要发起请求即可。
代码实现
抽象处理器
抽象处理器中包含了一个处理请求的方法,以及持有下一个处理者的引用。前者用于子类进行实现,链条中的每一个节点都应该有自己的处理逻辑,后者用于连接各个环节,我们可以通过该引用依次调用链条上的每个节点。
下面代码中的successor是处理请求的入口。这里可以根据自己的需要进行节点的选择。注意
public abstract class CommandHandler {
private CommandHandler next;
public CommandHandler(CommandHandler next) {
this.next = next;
}
public void successor(StringBuilder stringBuilder) {
handleRequest(stringBuilder);
if (this.next != null) {
this.next.successor(stringBuilder);
}
}
public abstract void handleRequest(StringBuilder stringBuilder);
}具体处理者
具体处理器实现handleRequest方法实现处理请求的逻辑。
public class Concretehandler1 extends CommandHandler {
public Concretehandler1(CommandHandler next) {
super(next);
}
@Override
public void handleRequest(StringBuilder stringBuilder) {
stringBuilder.append(" (handled by ConcreteHandler1)");
}
}客户端
public class Client {
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder("request info");
// 创建链条,commandHandler1-->commandHandler2-->null
CommandHandler commandHandler2 = new Concretehandler2(null);
CommandHandler commandHandler1 = new Concretehandler1(commandHandler2);
commandHandler1.successor(stringBuilder);
System.out.println(stringBuilder);
}
}结果:

注意:需要防止循环调用,否则会出现死循环。
CommandHandler commandHandler2 = new Concretehandler2(null);
CommandHandler commandHandler1 = new Concretehandler1(commandHandler2);
commandHandler2.setNext(commandHandler1);上面的代码产生了commandHandler1-->commandHandler2-->commandHandler1的循环。会导致StackOverflowError或者OOM。
因此抽象层中最好做循环校验,防止循环调用。比如我们将所有链接节点对象做下对比,看下地址是否相等。 比如:在设置下一个节点的时候,判断节点是否在当前节点的链接列表中,如果在,则不允许再次添加。
责任链模式与其他模式的对比
| 模式 | 功能 | 实现方式 | 适用场景 |
|---|---|---|---|
| 责任链模式 | 多个对象处理请求,避免发送者与接收者耦合 | 请求在处理者链中传递,每个处理者决定处理或传递 | 需要多个对象可能处理同一请求,且处理者不明确时 |
| 观察者模式 | 对象状态变化时通知观察者 | 主题维护观察者列表,状态变化时通知所有观察者 | 一个对象状态变化需要通知多个其他对象时 |
| 策略模式 | 封装可替换算法,客户端选择使用 | 定义算法族,客户端动态选择具体算法 | 需要在运行时根据条件选择不同算法时 |
| 命令模式 | 封装请求为对象,支持队列、撤销等操作 | 将请求封装为命令对象,调用者调用命令 | 需要支持请求的队列化、日志记录或撤销时 |
总结
核心思想
责任链模式的核心思想是将请求的发送者与接收者解耦,通过建立一个处理者链条,让请求在链中传递,直到有处理者能够处理它。这种模式允许系统在不明确指定请求处理者的情况下,将请求传递给多个可能的处理者进行处理。
主要角色
- 抽象处理者(AbstractHandler):定义处理请求的接口,包含处理请求的方法和对下一个处理者的引用
- 具体处理者(ConcreteHandler):实现抽象处理者,决定是否处理请求或传递给下一个处理者
- 请求(Request):包含需要处理的信息,处理者根据请求内容决定是否处理
- 客户端(Client):创建处理者链条并发起请求
实现方式
- 定义抽象处理者接口,包含处理请求的方法和设置下一个处理者的方法
- 实现具体处理者类,重写处理请求的方法,决定是否处理请求或传递给下一个处理者
- 客户端创建处理者对象,构建责任链
- 客户端将请求发送给链头的处理者,请求在链中传递
优缺点
优点:
- 降低了请求发送者与接收者之间的耦合度
- 提高了系统的灵活性,可以动态地调整责任链的结构
- 增强了系统的可扩展性,添加新的处理者只需添加新的具体处理者类
- 符合单一职责原则,每个处理者只需要关注自己能够处理的请求
缺点:
- 请求可能会在链中传递很长时间,导致性能问题
- 如果责任链构建不当,可能会导致请求无法被处理
- 责任链的调试和维护可能变得复杂
- 无法保证请求一定会被处理
适用场景
- 多个对象可能处理同一请求,但具体的处理者不确定
- 需要动态地指定处理者对象和处理顺序
- 需要避免请求的发送者与接收者之间的耦合
- 需要将请求的处理与请求的发送分离开
- 日志处理、权限控制、异常处理、表单验证等场景
实际应用
- 日志系统:不同级别的日志处理器组成责任链,处理不同级别的日志
- 权限控制系统:不同权限级别的处理器组成责任链,检查用户权限
- 异常处理:不同类型的异常处理器组成责任链,处理不同类型的异常
- 表单验证:多个验证器组成责任链,依次验证表单字段
- Servlet过滤器:多个过滤器组成责任链,对请求和响应进行处理
- Spring Security:安全过滤器链,处理认证和授权请求