介绍
责任链模式:使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连城一条链,并沿着这条链传递该请求,直到有对象处理它为止。
它是行为型设计模式之一。我们将多个节点首尾相连构成的模型称为链,而每个节点都可以拆开再连接。因此,链式结构具有很好的灵活性。将这样一种结构应用于编程领域,将每一个节点看作是一个对象,每一个对象拥有不同的处理逻辑,将一个请求从链式的首端发出,沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止。我们将这样的一种模式称为责任链模式。
使用场景
多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定。
在请求处理者不明确的情况下向多个对象中的一个提交一个请求。
需要动态指定一组对象处理请求。
优缺点
优点:对请求者和处理者关系解耦,提高代码的灵活性。
缺点:如果处理者太多,那么遍历必定会影响性能。
UML 关系图
简化版 UML 类图
根据类图我们可以得出如下简化版的通用模板代码:
角色介绍:
- Handler:抽象处理者角色,声明一个请求处理的方法,并在其中保持一个对下一个处理节点 Handler 对象的引用。
- ConcreteHandler:具体处理者角色,对请求进行处理,如果不能处理则将该请求转发给下一个节点上的处理对象。
完整版 UML 类图
上面的请求形式为固定的字符串,处理规则为该字符串是否与之匹配。然而在大多数情况下,责任链中的请求和对应的处理规则是不尽相同的,在这种情况下可以将请求进行封装,同时对请求的处理规则也进行封装作为一个独立的对象。类图如下:
对应模板代码如下:
下面是客户类:
对于责任链中的一个处理者对象,其只有两个行为:一是处理请求,而是将请求转发给下一个节点。不允许某个处理者对象在处理了请求后又将请求转发给上一个节点的情况。对于一条责任链来说,一个请求最终只有两种情况:一是被某个处理对象所处理,另一个是所有对象均未对其处理。前一种情况称之为纯的责任链,后一种情况称之为不纯的责任链。
示例
小先向组长报销 5 万元费用,组长一看是笔不小的数目,他没有权限审批,于是组长拿着票据去找部门主管;主管的权限内只能批五千以下的费用,于是主管又跑去找经理;经理权限也不够直接奔向老板的办公室。使用责任链模式的代码如下所示:
责任链模式的灵活之处在于请求的发起可以从责任链的任何一个节点处开始,同时也可以改变责任链内部传递的规则。比如,直接越过组长找主管报账,或者直接将经理设置为组长的上一级节点。
ANDROID 源码中的责任链模式实现
责任链模式在 ANDROID 源码中比较类似的实现莫过于对事件的分发处理,每当用户接触屏幕时,ANDROID 都会将对应的事件包装成一个事件对象从 ViewTree 的顶部自上而下地分发传递。而 ViewGroup 中执行事件派发的方法是 dispatchTouchEvent,在该方法中其对事件进行了统一的分发。
这里我们主要看看 dispatchTransformedTouchEvent 方法是如何调度子元素 dispatchTouchEvent 方法的。
ViewGroup 事件投递的递归调用就类似于一条责任链,一旦其寻找到责任者,那么将由责任者持有并消费掉该次事件,具体地体现在 View 的 onTouchEvent 方法中返回值的设置,如果 onTouchEvent 返回 false,那么意味着当前 View 不会是该次事件的责任人,将不会持有;如果为 true 则相反,此时 View 会持有该事件并不再向外传递。
责任链模式实战
ANDROID 中的 BroastCast 分为两种,一种是普通广播,另一种是有序广播。普通广播是异步的,发出时可以被所有的接收者收到。而有序广播是根据优先级依次传播的,直到有接收者将其终止或者所有接收者都不终止它。有序广播的这一特性与我们的责任链模式很相近,我们可以轻松地实现一种全局的责任链事件处理。