行为模式——责任链模式
1.意图
使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合。讲这些对象连成一条链,并沿着这条链传递请求。2.动机/功能
1. 用户界面中的上下文有关的帮助信息。用户在界面的任一部分上点击就可以得到帮助,所提供的的帮组依赖于点击的是界面的哪一部分以及其上下文。这里的问题是提交的对象并不明确知道谁才是最终提供帮助的对象。我们要提供一种办法将提交帮组的对象与可能提供帮助信息的对象解耦。
这一模式的想法是,给多个对象处理一个请求的机会,从而解耦发送者和接受者。该请求沿对象链传递直至其中一个对象处理它。
举个简单的例子,我们所谓的帮助,是基于某个子类或者父类而言,就好比如果有人问我们一个问题,我们不会,那我们可能会回家之后就去询问自己的父母,如果我们的父母知道问题的答案,就会给我们相应的解析,否则,我们父母就会把这个问题沿着这条家庭链传递上去。这就是责任链的简单例子。这是由于问题的发送者可以由很多人来做,但是谁都不能明确哪一个人才是真正理解这个问题的答案,所以责任链就允许这样的情况出现,不关心发送者和接受者之间的关系,只在自己的责任链中寻求可以解决发送者问题的接受者。
2. 自定义日志系统
这个是菜鸟网站上的一个例子,我觉得这个比较合适一点,毕竟在《Design Patterns》中的例子有点怪,可能自己理解的还不够,不能理解他这个例子的具体意思。
首先,传统的日志系统可能分为等级模式,比如INFO,ERROR,WARNING等,那么我们是够可以设计一个责任链,该链上包含许多的日志对象,根据我们使用的参数来调用相应对象的功能,已输出相应的日志。
3.适用性
1. 有多个对象可以处理一个请求那个对象处理该请求运行时刻自动确定。2. 在不明确指定接受者的情况下,向多个对象中的一个提交一个请求
3. 可处理一个请求的对象集合应被动指定。
优点:
1、降低耦合度。它将请求的发送者和接收者解耦。
2、简化了对象。使得对象不需要知道链的结构。
3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
4、增加新的请求处理类很方便。
缺点:
1、不能保证请求一定被接收。
2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。
3、可能不容易观察运行时的特征,有碍于除错。
4.结构
5.参与者
- Handler
—— 定义了一个处理请求的接口。
—— (可选) 实现后继者。 - ConcreteHandler
—— 处理它所负责的请求。
—— 可访问它的后继者。
—— 如果可以处理请求,则处理请求,否则将请求传递给下一个后继者。
6.协作
当客户提交一个请求时,请求会沿着责任链传递直至有一个ConcreteHandler对象负责处理它。
7.效果
-
降低耦合性。
该模式使得一个对象无需知道其他哪一个对象处理其请求。对象仅需要知道该请求会背“正确”地处理。接受者和发送者都没有对方明确的信息,且链中的对象不知道链的结构。 -
增强了给对象指派职责的灵活性。
可以通过运行时刻对该链进行动态的增加或修改来增加或改变处理一个请求的那些责职。 -
不保证被接受
不保证该请求会被接受,这是因为如果该链中不存在处理该请求的信号值,则会将请求抛弃,所以最好在链的尾端添加默认处理。
8.实现
- 实现后继链
a) 定义新的后继者链
b) 使用已有的连接 - 连接后继者
使用链表的形式进行连接。会在后面代码中体现。 - 表示请求
a) 信号值表示
比如上面说到的,可以使用一类宏定义或者常量来显示,如果要是用INFO日志信息,可以使用SIGN_LOG_INFO,这样的宏定义来定义请求。在接收方判断这个值是否为本身的值,是则处理该请求。
b) 接口表示
当一类请求需要处理的不仅仅是一两个简单的参数能描述的时候,就需要使用接口来描述。比如定义Request接口,继承这个接口的类都具有信号值以及需要处理的参数。
9.代码示例
由于CSDN本身贴不了代码,我就不把代码贴上来了,详细可见我的Github。
地址:https://github.com/VioletDream-SXZ/DesignPatterns
该代码的UML图如下:
参考文献
Erich Gamma,Richard Helm,Ralph Johnson,John Vissides.Design Patterns Elements of Reusable Object-Oriented Software[M].北京:机械工业出版社.2009:9.
菜鸟教程:https://www.runoob.com/design-pattern/chain-of-responsibility-pattern.html