欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

第9章 使编程更有灵活性——责任链模式

程序员文章站 2022-02-14 11:20:47
第9章 使编程更有灵活性——责任链模式责任链模式介绍责任链模式(Iterator Pattern),是行为型设计模式之一。什么是“链” ?我们将多个节点首尾 相连所构成的模型称为链,比如生活中常见的锁链,就是由一个个圆角长方形的铁环串起来的结构。 对于链式结构,每个节点都可以被拆开再连接,因此,链式结构也具有很好的灵活性。将这样一种 结构应用于编程领域,将每一个节点看作是一个对象,每一个对象拥有不同的处理逻辑,将一个请 求从链式的首端发出,沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止...

9.1 责任链模式介绍

责任链模式(Iterator Pattern),是行为型设计模式之一。什么是“链” ?我们将多个节点首尾相连所构成的模型称为链,比如生活中常见的锁链,就是由一个个圆角长方形的铁环串起来的结构。 对于链式结构,每个节点都可以被拆开再连接,因此,链式结构也具有很好的灵活性。将这样一种 结构应用于编程领域,将每一个节点看作是一个对象,每一个对象拥有不同的处理逻辑,将一个请 求从链式的首端发出,沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止, 我们将这样的一种模式称为责任链模式,这样的解释是不是更通俗易懂呢?我们还是看看责任链模式的标准定义。

9.2 责任链模式的定义

使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止

9.3 责任链模式的使用场景

  • 多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定。
  • 在请求处理者不明确的情况下向多个对象中的一个提交一个请求。
  • 需要动态指定一组对象处理请求。

9.4 责任链模式的UML类图

责任链模式的UML类图如图9-1所示。

根据类图我们可以得出如下一个责任链模式简化版的通用模式代码。
第9章 使编程更有灵活性——责任链模式
第9章 使编程更有灵活性——责任链模式
第9章 使编程更有灵活性——责任链模式
角色介绍

  • Handler:抽象处理者角色,声明一个请求处理的方法,并在其中保持一个对下一个处理节点Handler对象的引用。
  • ConcreteHandler:具体处理者角色,对请求进行处理,如果不能处理则将该请求转发给下一个节点上的处理对象。

上面我们说到这是一个简化版的通用模式代码,为什么这么说呢?因为对于请求来说,其形式是固定的,就是一个字符串,而判断一个节点上的对象是否能够处理该请求的标志,则是该字符串是否与之匹配。然而在大多数情况下,责任链中的请求和对应的处理规则是不尽相同的,在这种情况下可以将请求进行封装,同时对请求的处理规则也进行封装作为一个独立的对象,类图如图9-2所示。
第9章 使编程更有灵活性——责任链模式
首先我们来看AbstractHandler抽象处理者,其声明了处理者对象处理请求的方法和获取处理级别的方法,并对具体的处理转发逻辑进行了实现。
第9章 使编程更有灵活性——责任链模式
在这种情况下我们的责任转发逻辑由抽象处理类控制,而对于抽象请求者,其内部也声明了一个获取请求级别的方法,其与抽象处理者中返回的处理级别保持对应,什么级别的处理逻辑就对应什么样的请求级别。
第9章 使编程更有灵活性——责任链模式第9章 使编程更有灵活性——责任链模式
其他的就不多介绍了,我们分别实现了3个请求者和3个处理者对象,逻辑很简单。
第9章 使编程更有灵活性——责任链模式第9章 使编程更有灵活性——责任链模式
下面是客户类,具体的输出结果大家可以自行尝试,这里不再介绍。
第9章 使编程更有灵活性——责任链模式

9.5 责任链模式的简单实现

小民某天接到通知说需要出差去X国进修学习新技术,小民听到这消息心中一喜,于是收拾完背包后踏上了去X国进修的旅途。小民去X国学习一趟花费了近5万元,于是小民上班后的第一天就向组长申请报销费用,组长一看是笔不小的数目,他没有权限审批,于是组长就拿着票据去找部门主管,主管一看要报这么多钱,自己权限内只能批五千以下的费用,这完全超出了自己的权限范围,于是主管又跑去找经理,经理一看二话不说直接拿着票据奔向了老板的办公室,因为他也只能批一万以下的费用。类似的情况对上班族来说肯定并不少见,上面的这个情景其实就是一个责任链的小例子,每一个人,准确地说是每一类人代表这条链上的一个节点,小民是请求的发起者,而老板则是处于链条顶端的类,小民从链的底端开始发出一个申请报账的请求,首先由组长处理该请求, 组长比对后发现自己权限不够于是将该请求转发给位于链中下一个节点的主管,主管比对后也发现自己权限不够又将该请求转发给经理,而经理也基于同样的原因将请求转发给老板,这样层层转达直至请求被处理,从中大家可以看到一个显而易见的事,就是至始至终小民只与组长产生了关联,后面具体由谁处理的票据,小民并不关心,唯一在乎的是报账的结果,责任链模式在这里很好地将请求的发起者与处理者解耦。如果我们在代码中模拟这个过程也是很直观的,首先还是先声明一个抽象的领导类。
第9章 使编程更有灵活性——责任链模式在这个抽象的领导类中只做了两件事,一是定义了两个抽象接口方法来确定一个领导者应有的行为和属性,二是声明了一个处理报账请求的方法来确定当前领导是否有能力处理报账请求,如果没有这权限,则将该请求转发给上级领导处理。接下来则是各个领导类的实现。
第9章 使编程更有灵活性——责任链模式
最后,小民从组长开始发起请求申请报账。
第9章 使编程更有灵活性——责任链模式
第9章 使编程更有灵活性——责任链模式
这里大家可能会想,可不可以直接越过组长找主管报账呢?答案是肯定的,这也是责任链模式的灵活之处,请求的发起可以从责任链的任何一个节点处开始,同时也可以改变责任链内部传递的规则,如主管不在,我们完全可以跨过主管从组长直接将请求转送给经理。

对于责任链中的一个处理者对象,其只有两个行为,一是处理请求,二是将请求转送给下一个节点,不允许某个处理者对象在处理了请求后又将请求转送给上一个节点的情况。对于一条责任链来说,一个请求最终只有两种情况,一是被某个处理对象所处理,另一个是所有对象均未对其处理,对于前一种情况我们称该责任链为纯的责任链,对于后一种情况我们称为不纯的责任链,在实际应用中,我们所见到的责任链模式大多为不纯的责任链。

9.6 Android源码中的责任链模式实现

责任链模式在Android源码中比较类似的实现莫过于对事件的分发处理,每当用户接触屏幕时,Android都会将对应的事件包装成一个事件对象从ViewTree的顶部至上而下地分发传递,关于事件的包装我们会在命令模式中浅述,关于IMS对事件的处理我们也会在访问者模式中讲解,这里不再赘述,这里我们主要来看看ViewGroup中是如何将事件派发到子View的,我们知道ViewGroup中执行事件派发的方法是dispatchTouchEvent,在该方法中其对事件进行了统一的分发
第9章 使编程更有灵活性——责任链模式第9章 使编程更有灵活性——责任链模式
第9章 使编程更有灵活性——责任链模式
第9章 使编程更有灵活性——责任链模式
这里我们上要看看dispatchTransfomedTouchEvent方法是如何调度子元素dispatchTouchEvent方法的
第9章 使编程更有灵活性——责任链模式
第9章 使编程更有灵活性——责任链模式
ViewGroup事件投递的递归调用就类似于一条责任链,一旦其寻找到责任者,那么将由责任者持有并消费掉该次事件,具体地体现在View的onTouchEvent方法中返回值的设置,如果onTouchEvent返回false,那么意味着当前View不会是该次事件的责任人,将不会对其持有;如果 为true则相反,此时View会持有该事件并不再向外传递

9.7 责任链模式实战

责任链模式与其说在Android中的应用倒不如说是在Java中的应用,毕竟上层应用开发大多都是基于Java的,而我们的设计模式也是针对Java而言,如果你有兴趣,完全可以使用责任链模式来替代各种分支或条件判断语句,不过大多数情况下这都是多此一举的。Android中我们可以借鉴责任链模式的思想来优化BroadcastReceiver使之成为一个全局的责任链处理者,具体方法很简单,我们知道Broadcast可以被分为两种,一种是Normal Broadcast普通广播,另一种是Ordered Broadcast有序广播,普通广播是异步的,发出时可以被所有的接收者收到;而有序广播则是根据优先级依次传播的,直到有接收者将其终止或所有接收者都不终止它,有序广播的这一特性与我们的责任链模式很相近,通过它可以轻松地实现一种全局的责任链事件处理,这里我们创建3个BroadcastReceiver。
第9章 使编程更有灵活性——责任链模式
第9章 使编程更有灵活性——责任链模式
在发送广播的时候我们在Intent中附加两个值,一个int类型的值用于存储权限值,另一个String类型的则存储消息,一个接收者能否处理本次广播的唯一条件则是看广播中所附加的权限值是否与自身的相等,如上面FirstReceiver的处理权限值为1000,则只有当limit = 1000时才会处理本次广播,否则在广播的Intent中再附加一条信息传播出去给下一个接收者。
第9章 使编程更有灵活性——责任链模式
第9章 使编程更有灵活性——责任链模式
最后我们还要在AndroidManifest.xml文件中声明这3个Receiver,并设定对应的权限值。
第9章 使编程更有灵活性——责任链模式
完成后,我们在一个Activity中发送一个广播。
第9章 使编程更有灵活性——责任链模式
这里我们将limit设置为100,也就是说只有SecondReceiver才会处理它,具体效果这里就不演示了,大家可以自行尝试。

9.8 小结

世界不是完美的,所以不会有完美的事物存在。就像所有的设计模式一样,有优点也有缺点,但总体来说,优点必定大于缺点或者说缺点相对于优点来说更可控。责任链模式也一样,优点显而易见,可以对请求者和处理者关系解耦,提高代码的灵活性。责任链模式的最大缺点是对链中请求处理者的遍历,如果处理者太多,那么遍历必定会影响性能,特别是在一些递归调用中,要慎重

本文地址:https://blog.csdn.net/aha_jasper/article/details/111873782