一 概述
责任链模式是一个相对比较简单的模式,它的名字已经非常好的暗示了其工作原理。每个处理器互相首尾连接在一起成为一条链,然后任务顺着这条链往下传,直到被某个处理器处理掉。
1.1 定义
避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
- 责任链模式属于行为型模式
- 多个对象中,每个对象都持有下一个对象的引用,这就构成了 “链” 这种结构
- 一个请求通过链的头部,一直往下传递到链上的每一个结点,直到有某个结点对这个请求做出处理为止,这就是责任链模式
- 责任链模式一般分为处理者与请求者。具体的处理者分别处理请求者的行为
1.2 使用场景
一个请求需要被多个对象中的某一个处理,但是到底是哪个对象必须在运行时根据条件决定。
1.3 UML 类图
角色说明:
- Handler(抽象处理者):抽象类或者接口,定义处理请求的方法以及持有下一个 Handler 的引用
- ConcreteHandler1,ConcreteHandler2(具体处理者):实现抽象处理类,对请求进行处理,如果不处理则转发给下一个处理者,有多少个处理器,就定义多少个这样的类
- Client (客户端):即要使用责任链模式的地方
责任链模式唯一的难点就是怎么将很多处理器对象连成一条链。
接下来,我们来看责任链模式是如何实现的。
二 实现
王二狗本来是干 Android 开发的,最近公司想让他把 IOS 的活也干了,但是 Windows 笔记本不能开发 IOS,所以二狗提出买一台 Mac 笔记本电脑。这花钱的事需要领导审批,而每个领导权限不一样,能够审批的最大金额有限制。二狗首先肯定是向自己的小组 leader 提出,但是由于金额太大,超出了他的审批权限。于是小组领导就去找自己的领导,部门经理,但是部门经理也权限不够,最后到了 CFO 那里。。。
王二狗遇到的情况就非常适合使用责任链模式。二狗这个预算申请的请求,事先不知道会由哪层领导处理,而各层领导的审批职责就好像铁链一样连接在一起,一个预算请求沿着这条链一直往上传。。。让我们用代码来实现上面的场景吧。
2.1 设计一个所有处理器都要实现的接口
public interface BudgetHandler {
void setNextHandler(BudgetHandler nextHandler);
boolean handle(int amount);
}
其中 setNextHandler(BudgetHandler) 方法负责设置下一个处理器,以便在自己不能处理此请求的情况下,将请求交给下一个处理器。handle(int) 方法负责处理请求。
2.2 实现各种处理器
1、小组领导类:
public class GroupLeader implements BudgetHandler {
private BudgetHandler nextHandler;
@Override
public void setNextHandler(BudgetHandler nextHandler) {
this.nextHandler = nextHandler;
}
@Override
public boolean handle(int amount) {
Objects.requireNonNull(nextHandler);
if(amount<1000){
System.out.println("小钱,批了!");
return true;
}
System.out.println(String.format("%d超出GroupLeader权限,请更高级管理层批复",amount));
return nextHandler.handle(amount);
}
}
可见,小组领导最多可以批1000块以下的预算,再多了就批不了了。
2、经理类:
public class Manager implements BudgetHandler {
private BudgetHandler nextHandler;
@Override
public void setNextHandler(BudgetHandler nextHandler) {
this.nextHandler = nextHandler;
}
@Override
public boolean handle(int amount) {
Objects.requireNonNull(nextHandler);
if(amount<5000){
System.out.println("小于2000块,我这个经理可以决定:同意!");
return true;
}
System.out.println(String.format("%d超出Manager权限,请更高级管理层批复",amount));
return nextHandler.handle(amount);
}
}
经理最多可以批5000块以下的预算。
3、首席财务官类:
public class CFO implements BudgetHandler {
private BudgetHandler nextHandler;
@Override
public void setNextHandler(BudgetHandler nextHandler) {
this.nextHandler = nextHandler;
}
@Override
public boolean handle(int amount) {
if(amount<50000){
System.out.println("CFO同意,希望你再接再厉,为公司做出更大的贡献。");
return true;
}
if (nextHandler!=null){
return nextHandler.handle(amount);
}
//已经没有更高级的管理层来处理了
System.out.println(String.format("%d太多了,回去好好看看能不能缩减一下",amount));
return false;
}
}
2.3 客户端
每个处理器都建好了,那么怎么才能让他们连成链呢?这就是客户端的责任了。
public class DogWang2Cor {
public void applyBudget() {
GroupLeader leader = new GroupLeader();
Manager manager = new Manager();
CFO cfo = new CFO();
leader.setNextHandler(manager);
manager.setNextHandler(cfo);
System.out.println(String.format("领导好:由于开发需求,需购买一台Mac电脑,预算为%d 望批准", 95000));
if (leader.handle(95000)) {
System.out.println("谢谢领导");
} else {
System.out.println("巧妇难为无米之炊,只能划船了...");
}
}
}
输出结果:
领好:由于开发需求,需购买一台Mac电脑,预算为20000 望批准
20000超出GroupLeader权限,请更高级管理层批复
20000超出Manager权限,请更高级管理层批复
CFO同意,希望你再接再厉,为公司做出更大的贡献。
谢谢领导
首先,二狗不知道谁最终会批准这笔预算,但是他知道入口肯定是他的小组领导,小组领导上一级就是经理,再上一级是 CFO。
所以在 Handler 中使用 setNextHandler 方法指定下一个 Handler,最后由于 CFO 是最后一个处理器,所以我们就不设置 Handler。最终二狗拿到了自己心仪的 Mac 笔记本电脑。。。
三 总结
3.1 特点
- Handler 接口持有它自己的类型,通过 set 方法或者构造函数将责任链上的下一个处理器赋值进去
- 客户端负责将各个处理器连成链,而且必然知道链上的第一个处理器,通过调用它的 handle 方法触发处理流程
- 注意千万不能将链搞成一个环(将最后一个处理的下一个 handler 设置为第一个),那样就无法结束了
3.2 优点
- 代码的解耦,请求者与处理者的隔离分开
- 一个命令可以被多个处理器执行,例如各种框架中的拦截器
- 易于扩展,新增处理者往链上加结点即可
3.3 缺点
- 类增多了
- 责任链过长的话,或者链上的结点判断处理时间太长的话会影响性能,特别是递归循环的时候
- 请求有可能遍历完链都得不到处理,也有可能链变成环,循环处理
四 Android 中源码实例分析
Android 中的事件分发机制就是类似于责任链模式,关于事件分发机制,这里先不详述了,先占个坑,后面另起文章说明。
另外,OKhttp 中对请求的处理也是用到了责任链模式,有兴趣的可以去看下 OKhttp 的源码。后面有时间也会对 OKhttp 的源码进行分析。