🔥 核心
责任链上的每个处理者都拥有下一个处理者的引用。
请求被放到责任链上,如果当前处理者无法处理该请求,那么它会把请求传送给下一个处理者,以此类推。
🙁 问题场景
一家大型商场发生了火灾。
幸运的是,火灾发生在深夜,所以没有人受伤;但货架上可怜的商品就没这么幸运了,它们都被烧毁,损失达到了一亿美元。市民们上街游行,谴责政府对商场的安全问题监督不善。
办公室里的官员们焦头烂额,不知道该如何处理这件事情…
🙂 解决方案
好在,政府有一个完整的上报制度。这是一个链状的结构。
区长
最先得知了事故的发生,他惊慌失措,完全没有遇到过这么大的安全事故,于是他将问题上报给了 市长
;
市长
挂断了电话后,意识到问题的严重性完全超过了自己的职责范围,于是他又拨通了 州长
的电话;
州长
弄明白事故的缘由后,思考片刻,认为这件事情对全国都有警示意义,于是他又给 总统
发送了电报。
总统
接受到电报后,立即召开紧急会议,并给出了一套完整的解决方案。
最终,商场火灾事件得到了妥善的处理。
你会发现,在整个事件处理过程中,市民与官员、甚至官员之间并没有过多的耦合,市民只需要将请求放到责任链上即可,请求会自动进行传递,直至被处理———这就是责任链模式的魅力。
🌈 有趣的例子
如果你对国家层面的追责制度并不了解,那我们就举个身边的例子——学校里的 助理(Aid)
、主任(Dean)
、校长(Master)
如何 处理(handle())
学校里的各个事件。
核心的原则是,如果某个职位的 权力(power)
大于等于事件的 等级(level)
,就在当前职位处理这个事件;否则交给上级处理。
领导(抽象类)
abstract class Leader {
// 权力
protected int power;
// 下一个处理者
private Leader nextLeader;
public void setNextLeader(Leader leader) {
nextLeader = leader;
}
public Leader getNextLeader() {
return nextLeader;
}
public void handle(int level) {
if (power >= level) {
System.out.println("我已经处理了这件事情(^_^)");
} else if (this.getNextLeader() != null) {
System.out.println("我处理不了这件事情,但我把它汇报给了上级(>_<)");
this.getNextLeader().handle(level);
} else {
System.out.println("这件事情没有得到解决(#_#)");
}
}
}
助理
class Aid extends Leader {
public Aid() {
this.power = 2;
}
@Override
public void handle(int level) {
System.out.println("我是助理");
super.handle(level);
}
}
主任
class Dean extends Leader {
public Dean() {
this.power = 6;
}
@Override
public void handle(int level) {
System.out.println("我是主任");
super.handle(level);
}
}
校长
class Master extends Leader {
public Master() {
this.power = 10;
}
@Override
public void handle(int level) {
System.out.println("我是校长");
super.handle(level);
}
}
public class ChainPatternDemo {
public static void main(String[] args) {
// 生成几个领导对象
Leader aid = new Aid();
Leader dean = new Dean();
Leader master = new Master();
// 组成责任链
aid.setNextLeader(dean);
dean.setNextLeader(master);
// 请求放到责任链上
aid.handle(9);
}
}
我是助理
我处理不了这件事情,但我把它汇报给了上级(>_<)
我是主任
我处理不了这件事情,但我把它汇报给了上级(>_<)
我是校长
我已经处理了这件事情(^_^)
☘️ 使用场景
◾️当程序需要使用不同方式处理不同种类请求,而且请求类型和顺序预先未知时,可以使用责任链模式。
该模式能将多个处理者连接成一条链。接收到请求后,它会“询问”每个处理者是否能够对其进行处理。这样所有处理者都有机会来处理请求。
◾️当必须按顺序执行多个处理者时,可以使用该模式。
无论你以何种顺序将处理者连接成一条链,所有请求都会严格按照顺序通过链上的处理者。
◾️如果所需处理者及其顺序必须在运行时进行改变,可以使用责任链模式。
如果在处理者类中有对引用成员变量的设定方法,你将能动态地插入和移除处理者,或者改变其顺序。
🧊 实现方式
(1)声明处理者接口并描述请求处理方法的签名。
- 确定客户端如何将请求数据传递给方法。最灵活的方式是将请求转换为对象,然后将其以参数的形式传递给处理函数。
(2)为了在具体处理者中消除重复的样本代码,你可以根据处理者接口创建抽象处理者基类。
- 该类需要有一个成员变量来存储指向链上下个处理者的引用。你可以将其设置为不可变类。但如果你打算在运行时对链进行改变,则需要定义一个设定方法来修改引用成员变量的值。
- 为了使用方便,你还可以实现处理方法的默认行为。如果还有剩余对象,该方法会将请求传递给下个对象。 具体处理者还能够通过调用父对象的方法来使用这一行为。
(3)依次创建具体处理者子类并实现其处理方法。每个处理者在接收到请求后都必须做出两个决定:
- 是否自行处理这个请求。
- 是否将该请求沿着链进行传递。
(4)客户端可以自行组装链,或者从其他对象处获得预先组装好的链。在后一种情况下,你必须实现工厂类以根据配置或环境设置来创建链。
(5)客户端可以触发链中的任意处理者,而不仅仅是第一个。请求将通过链进行传递,直至某个处理者拒绝继续传递,或者请求到达链尾。
(6)由于链的动态性,客户端需要准备好处理以下情况:
- 链中可能只有单个链接。
- 部分请求可能无法到达链尾。
- 其他请求可能直到链尾都未被处理。
🎲 优缺点
➕ 你可以控制请求处理的顺序。
➕ 降低耦合度,它将请求的发送者和接收者解耦。
➕ 简化了对象,使得对象不需要知道链的结构。
➕ 单一职责原则。你可对发起操作和执行操作的类进行解耦。
➕ 开闭原则。你可以在不更改现有代码的情况下在程序中新增处理者。
➖ 部分请求可能未被处理。
➖ 可能会造成循环调用。
➖ 可能不容易观察运行时的特征,有碍于除错。
🌸 补充
你和责任链其实是老朋友了——JS的DOM树冒泡,Servlet的Filter过滤器,Spring中的Interceptor拦截器…