一、责任链模式的定义
二、责任链模式的使用场景
三、责任链模式UML类图
四、责任链模式具体实例
五、责任链模式代码实现
- 抽象领导者
2.具体领导者,继承自抽象领导者类
六、责任链模式优缺点
七、总结
之前计划先把设计模式学完,但是感觉设计模式毕竟这么多种,粗略过一遍又不太好,所以决定还是先学自己需要学的Android知识点,在学习的过程中遇到了哪种设计模式再来学习,感觉这样效率会高一点,而且更容易自己理解。昨天在研究Android事件分发机制时发现Android事件分发机制是一种典型的责任链模式。于是特意在去学习责任链模式,所以就有了这篇文章,这文章基本都是参照《Android源码设计模式解析与实战》一书。
一、责任链模式的定义
使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
二、责任链模式的使用场景
多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定。
在请求处理者不明确的情况下向多个对象中的一个提交一个请求。
需要动态指定一组对象处理请求。
三、责任链模式UML类图
示意图:
四、责任链模式具体实例
看了这么多概念性的东西总觉得优点懵逼,接下来引用书上的一个例子,感觉特别简单明了。
栗子:小群某天接到通知说要去国外进修学习新技术,小群听到这消息心中暗喜,表面上还是假装很镇定,于是她特意问了一下公司是否报销,在得到了肯定的答案之后小群背上背包踏上了去国外的进修之旅。小群这趟去国外学习一趟花了近10万块,于是小群上班后的第一天就是找公司报销,向组长申请报销费用,组长一看这么大一笔钱,他哪里有这个权限,他手里最多才可以批1000块,于是组长就拿着票据去找部门主管,主管一看要报这么多钱,自己权限内只能批1万以下的费用,这完全超出了自己的权限范围呀,于是又只得去找上一级也就是经理,经理一看,我也只能批5万以下的费用啊。于是二话不说拿着票据直接奔向了老板的办公室,让老板去处理小群的这个请求。上面的这个情景就是一个责任链的小栗子,每一个人,准确的说是每一类人代表这条链上的一个节点,小群是请求的发起者,而老板也就是我们的大BOSS则是处于链条顶端的类,小群从链的底端开始发出一个申请报账的请求,首先由组长处理该请求,组长比对后发现自己权限不够,于是将该请求转发给位于该链中下一个节点的主管,主管比对后发现自己权限也不够,又只能将该请求转发给经理,而经理同样权限不够,毕竟10万块的大数目只有老板能处理,于是最后经理又将请求转发给了老板,这样层层转达直到请求被处理。从中大家可以看到一个显而易见的事,就是至始至终小群只与组长产生了关联,后面具体由谁处理报销的票据,小群并不关心,小群只关心自己的票据(请求)有没有被成功处理。责任链模式在这里很好的将请求的发起者和处理者解耦。接下来我们用代码来实现这一过程。
五、责任链模式代码实现
- 抽象领导者
/**
* 抽象的领导类,即UML图中的Hanlder
*/
public abstract class Leader {
protected Leader nextHandler;//上一级领导(处理者),UML图中的successor
/**
* 处理报账请求
* @param money 报账额度
* 申明为final,子类无法重写
*/
public final void handleRequest(double money){
if(money<=limit()){
handle(money);
}else{
if(null!=nextHandler){//有上一级处理者
nextHandler.handleRequest(money);
}else{
Log.e(getClass().getSimpleName(),"没有领导能批复你的票据报销啦,自己去报销吧!");
}
}
}
/**
* 自身能批复的报账额度
* @return 额度
*/
public abstract double limit();
/**
* 处理报账行为
* @param money 报账额度
*/
public abstract void handle(double money);
}
在这个抽象的领导类中只做了两件事,一是定义了两个抽象接口方法来确定一个领导者应有的行为和属性,二是声明了一个处理报账请求的方法来确定当前领导是否有能力处理报账请求,如果没有这权限,则将该请求转发给上级领导处理。接下来是各个具体的领导类的实现。
2.具体领导者,继承自抽象领导者类
/**
* 组长
*/
public class GroupLeader extends Leader {
@Override
public double limit() {
return 1000;
}
@Override
public void handle(double money) {
Log.e(getClass().getSimpleName(),"组长批复报销了你的"+money+"元");
}
}
/**
* 主管
*/
public class Director extends Leader {
@Override
public double limit() {
return 10000;
}
@Override
public void handle(double money) {
Log.e(getClass().getSimpleName(),"主管批复报销了你的"+money+"元");
}
}
/**
* 经理
*/
public class Manager extends Leader {
@Override
public double limit() {
return 50000;
}
@Override
public void handle(double money) {
Log.e(getClass().getSimpleName(),"经理批复报销了你的"+money+"元");
}
}
/**
* 大BOSS
*/
public class Boss extends Leader {
@Override
public double limit() {
return 999999;
}
@Override
public void handle(double money) {
Log.e(getClass().getSimpleName(),"老板批复报销了你的"+money+"元");
}
}
具体领导类创建后,小群从组长开始发起请求申请报账,代码如下:
public class XiaoQun extends BaseActivity {
@Override
protected int getLayoutId() {
return R.layout.chain_of_responsibility_model_activity;
}
@Override
protected void initView() {
setToolBarTitle("责任链模式");
}
@Override
protected void init() {
GroupLeader groupLeader = new GroupLeader();
Director director = new Director();
Manager manager = new Manager();
Boss boss = new Boss();
//设置上一级领导(处理者)对象
groupLeader.nextHandler = director;
director.nextHandler = manager;
manager.nextHandler = boss;
//发起报账申请
groupLeader.handleRequest(100000);
}
}
最后运行结果如下:
可以看到最后是BOSS处理了小群的报账申请,而且也只有BOSS才有这个权限处理,但是这里小群在申请的时候却只和组长进行了交流,降低了耦合度,这也是责任链模式的优点。当然这里我们代码也可以直接越过组长找主管或者经理或者直接找BOSS报账也是可以的,这也是责任链模式的灵活之处,请求的发起可以从责任链的任何一个节点开始,同时也可以改变责任链内部传递的规则,如主管不在,我们完全可以跨过主管直接将请求转送给经理。
六、责任链模式优缺点
优点
- 降低耦合度:客户端不需要知道请求由哪个处理者处理,而处理者也不需要知道处理者之间的传递关系,由系统灵活的组织和分配。
- 良好的扩展性:增加处理者的实现很简单,只需重写处理请求业务逻辑的方法。
缺点 - 请求会从链头发出,直到有处理者响应,在责任链比较长的时候会影响系统性能。
- 请求递归,调试排错比较麻烦。
七、总结
对于责任链中的一个处理者对象,其只有两个行为,一是处理请求,二是将请求转送给下一个节点,不允许某个处理者对象在处理了请求后又将请求转送给上一级节点的情况。对于一条责任链来说,一个请求最终只有两种情况,一是被某个处理对象所处理,另一个是所有对象均未对其处理,对于前一种情况我们称该责任链为纯的责任链,对于后一种情况我们称为不纯的责任链,在实际应用中,我们所见到的责任链模式大多为不纯的责任链。