23.2 解 决 方 案

23.2.1 使用职责链模式来解决问题

用来解决上述问题的一个合理的解决方案,就是使用职责链模式。那么什么是职责链模式呢?

1.职责链模式的定义

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

2.应用职责链模式来解决问题的思路

仔细分析上面的场景,当客户端提出一个聚餐费用的申请,后续处理这个申请的对象项目经理、部门经理和总经理,自然地形成了一个链,从项目经理→部门经理→总经理,客户端的申请请求就在这个链中传递,直到有领导处理为止。看起来,上面的功能要求很适合采用职责链来处理这个业务。

要想让处理请求的流程可以灵活地变动,一个基本的思路,那就是动态构建流程步骤,这样随时都可以重新组合出新的流程来。而要让处理请求的对象也要很灵活,那就要让它足够简单,最好是只实现单一的功能,或者是有限的功能,这样更有利于修改和复用。

职责链模式就很好地体现了上述的基本思路,首先职责链模式会定义一个所有处理请求的对象都要继承实现的抽象类,这样就有利于随时切换新的实现;其次每个处理请求对象只实现业务流程中的一步业务处理,这样使其变得简单;最后职责链模式会动态地来组合这些处理请求的对象,把它们按照流程动态地组合起来,并要求它们依次调用,这样就动态地实现了流程。

这样一来,如果流程发生了变化,只要重新组合就可以了;如果某个处理的业务功能发生了变化,一个方案是修改该处理对应的处理对象;另一个方案是直接提供一个新的实现,然后在组合流程的时候,用新的实现替换掉旧的实现就可以了。

23.2.2 职责链模式的结构和说明

职责链模式的结构如图23.1所示。

图片

图23.1 职责链模式结构图

■ Handler:定义职责的接口,通常在这里定义处理请求的方法,可以在这里实现后继链。

■ ConcreteHandler:实现职责的类,在这个类中,实现对在它职责范围内请求的处理,如果不处理,就继续转发请求给后继者。

■ Client:职责链的客户端,向链上的具体处理对象提交请求,让职责链负责处理。

23.2.3 职责链模式示例代码

(1)先来看看职责的接口定义。示例代码如下:

dedcc394c7024c90a6e6f50d0917b57e

(2)再来看看具体的职责实现对象。示例代码如下:

4e6783f2408b4972b85ba16f67b23ac6

17197220168e4610aecce0e1a74b3f41

另外,ConcreteHandler2和ConcreteHandler1的示意代码几乎是一样的,因此就不再赘述。

(3)接下来看看客户端的示意。示例代码如下:

fc694f62d07e43cd881e393167bc95fb

23.2.4 使用职责链模式重写示例

要使用职责链模式来重写示例,先来实现如下的功能:当某人提出聚餐费用申请的请求后,该请求会在项目经理→部门经理→总经理这样一条领导处理链上进行传递,发出请求的人并不知道谁会来处理他的请求,每个领导会根据自己的职责范围,来判断是处理请求还是把请求交给更高级的领导,只要有领导处理了,传递就结束了。

需要把每位领导的处理独立出来,实现成单独的职责处理对象,然后为它们提供一个公共的、抽象的父职责对象,这样就可以在客户端来动态地组合职责链,实现不同的功能要求了。还是看一下示例的整体结构,有助于对示例的理解和把握,如图23.2所示。

图片

图23.2 使用职责链模式的示例程序的结构示意图

1.定义职责的抽象类

首先来看看定义所有职责的抽象类,也就是所有职责的外观,在这个类中持有下一个处理请求的对象,同时还要定义业务处理方法。示例代码如下:

a81ccc0653064bda976db0e34fdd9d8e

2.实现各自的职责

现在实现的处理聚餐费用流程是:申请人提出的申请交给项目经理处理,项目经理的处理权限是500元以内,超过500元,把申请转给部门经理处理,部门经理的处理权限是1000元以内,超过1000元,把申请转给总经理处理。

分析上述流程,该请求主要有三个处理环节,把它们分别实现成为职责对象,一个对象实现一个环节的处理功能,这样就会比较简单。

先看看项目经理的处理吧。示例代码如下:

95193330e6154ddea6d9720c6061d0bb

接下来看看部门经理的处理。示例代码如下:

c04cbf66e8ce4caaaa6d5fb8db18c56f

9c8fdac746bb407799010536d8d94f91

再看总经理的处理示例代码如下:

0821a7922b4549419c9e9724227f197e

3.使用职责链

那么客户端如何使用职责链呢,最重要的就是要先构建职责链,然后才能使用。示例代码如下:

2253e200557d4570a303aef4f268897e

97f5ce209eac444c8d78ede756e1e4ac

运行结果如下:

57d79a9fe8af42ca8c347b29e88843bd

看起来结果跟前面不用模式的实现方案的运行结果是一样的,它们本来就是实现的同样的功能,只不过实现方式不同而已。

4.如何运行的

理解了示例的整体结构和具体实现,那么示例的具体运行过程是怎样的呢?

下面就以“小李申请聚餐费用1200元”这个费用申请为例来说明。调用过程的示意图如图23.3所示。

图片

图23.3 职责链示例调用过程示意图