《设计模式》— 行为型模式 — 责任链模式

一、动机

考虑一个图形用户界面的上下文有关的帮助机制。用户在界面的任一部分点击就可以得到帮助信息,所提供的帮助依赖于点击的是界面的哪一部分及其上下文。例如,对话框中按钮的帮助信息就可能和主窗口中类似的按钮不同。如果对那一部分界面没有特定的帮助信息,那么帮助系统应该显示一个关于当前上下文的较一般的帮助信息。

因此,很自然地,应根据普遍性从最特殊到最普遍的顺序来组织帮助信息。而且,很明显,在这些用户界面对象中会有一个对象来处理帮助请求,至于是哪一个对象则取决于上下文以及可用的帮助具体到何种程度。

这里的问题是提交帮助请求的对象并不明确知道谁是最终提供帮助的对象。我们要有一种办法将提交帮助请求的对象与可能提供帮助信息的对象解耦 —— 责任链模式。

这一模式的想法是,给多个对象处理一个请求的机会,从而解耦发送者和接受者。该请求沿对象链传递直至其中一个对象处理它。从第一个对象开始,链中收到请求的对象要么亲自处理它,要么转发给链中的下一个候选者。提交请求的对象并不明确的知道哪一个对象将会处理它 —— 因此我们说该模式有一个隐式的接受者。

要沿链转发请求,并保证接受者为隐式的,每个在链上的对象都有一致的处理请求和访问链上后继者的接口。例如,帮助系统可以定义一个带有相应的 handleHelp 操作的 HelpHandler 类。HelpHandler 可以是所有候选对象类的父类,或者它可被定义为一个混入类。这样想处理帮助请求的类就可以将 HelpHandler 作为其父类,如下图所示。
在这里插入图片描述
这里我们可以在 HelpHandler 类中保存一个 handler,用于保存处理该请求的后继类对象。

二、适用性

  • 有多个对象可以处理一个请求,哪个对象处理该请求运行是自动确定。
  • 你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
  • 可处理一个请求的对象集合应该被动态指定。

三、结构

在这里插入图片描述

四、参与者

1、Handler

  • 定义一个处理请求的接口。
  • 实现后继链。

2、ConcreteHandler

  • 处理它所负责的请求。
  • 可访问它的后继者。
  • 如果可处理该请求,就处理之;否则将请求转发给它的后继者。

3、Client

提交请求

五、效果

1、降低耦合度

该模式使得一个对象无需知道是其他哪一个对象处理其请求。对象仅需要知道该请求会被正确地处理。接受者和发送者都没有对方的明确信息,且链中的对象不需要知道链的结构。

2、增加了给对象指派职责的灵活性

当在对象中分派职责时,职责链给你更多的灵活性。你可以通过在运行时对该链进行动态的增加或修改来增加或改变处理一个请求的那些职责。你可以将这种机制与静态的特例化处理对象的继承机制结合起来使用。

3、不保证被接受

既然一个请求没有明确的接受者,那么久不能保证它一定会被处理 —— 该请求可能一直到链的末端都得不到处理。一个请求也可能因该链没有被正确配置而得不到处理。

六、实现

1、实现后继者链

有两种方式可以实现后继者链:

  • 定义新的链接(可以在基类中定义)
  • 使用已有的链接

我们前面讨论了如何通过定义新的链接实现后继者链。此外,在组合模式中,我们可以通过将父组件引用设置为后继者实现职责链。

2、连接后继者

如果没有已有的引用可定义一个链,那么你必须自己引入它们。这种情况下 Handler 不仅定义该请求的接口,通常也维护后继者。这样 handler 就提供了 handleRequest 的默认实现:handlerRequest 向后继者转发请求。如果 ConcreteHandler 对该请求不感兴趣,它不需要重定义转发操作,因为它的默认实现进行无条件的转发。

3、表示请求

可以有不同的方式表示请求。最简单的形式就是使用硬编码,例如我们前面直接调用 handleHelp 来处理帮助的请求,并调用后继者的响应方法进行转发。这种形式方便且很安全,但是不易扩充。

另一种方法是选择使用一个处理函数。我们可以通过不同的枚举常量来区分不同类型的请求。我们可以通过增加枚举类型的常量值来增加请求。但是发送发和接受方要在如何对请求编码上达成一致。在这种实现中,我们可以使用一个类封装请求对象,并暴露一个接口用于获取请求类型。

七、应用

责任链模式最常见的应用就是在事件处理的系统中。无论是在 windows 系统中,还是浏览器交互中,用户的点击事件被触发后并不是仅被当前点击的窗体捕获,而是会沿着其父对象(或者子对象,取决于事件传递的模式)继续传递,直到到达末尾或有窗体显式地阻止该事件继续传递。

此外,现在基本所有语言都支持异常。异常处理其实也应用了责任链模式。当异常发生时,会发生栈接退。该异常会在栈上不断地向调用函数传递,直到有函数捕获了该异常,或者最终被系统的异常处理函数捕获,调用 terminate 终止进程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值