sugar/ 九月 27, 2019/ python设计模式/ 0 comments

在广播计算机网络中,会将所有请求发送给所有节点(简单起见,不考虑广播域),但仅对所发送请求感兴趣的节点会处理请求。加入广播网络的所有计算机使用一种常见的媒介相互连接,比如,下图中的三个节点通过光缆连接起来。

如果一个节点对某个请求不感兴趣或者不知道如何处理这个请求,可以执行以下两个操作。

  • 忽略这个请求,什么都不做
  • 将请求转发给下一个节点

节点对一个请求的反应方式是实现的细节。然而,我们可以使用广播计算机网络的类比来理解责任链模式是什么。责任链(Chain of Responsibility)模式用于让多个对象来处理单个请求时,或者用于预先不知道应该由哪个对象(来自某个对象链)来处理某个特定请求时。其原则如下所示。

  1. 存在一个对象链(链表、树或任何其他便捷的数据结构)。
  2. 我们一开始将请求发送给链中的第一个对象。
  3. 对象决定其是否要处理该请求。
  4. 对象将请求转发给下一个对象。
  5. 重复该过程,直到到达链尾。

在应用级别,不用讨论光缆和网络节点,而是可以专注于对象以及请求的流程。下图展示了客户端代码如何将请求发送给应用的所有处理元素(又称为节点或处理程序)。

注意,客户端代码仅知道第一个处理元素,而非拥有对所有处理元素的引用;并且每个处理元素仅知道其直接的下一个邻居(称为后继),而不知道所有其他处理元素。这通常是一种单向关系,用编程术语来说是一个单向链表,与之相反的是双向链表。单向链表不允许双向地遍历元素,双向链表则是允许的。这种链式组织方式大有用处:可以解耦发送方(客户端)和接收方(处理元素)。

现实生活中的例子

ATM机以及及一般而言用于接收/返回钞票或硬币的任意类型机器(比如,零食自动贩卖机)都使用了责任链模式。机器上总会有一个放置各种钞票的槽口,如下图所示:

钞票放入之后,会被传递到恰当的容器。钞票返回时,则是从恰当的容器中获取。我们可以把这个槽口视为共享通信媒介,不同的容器则是处理元素。结果包含来自一个或多个容器的现金。例如,在上图中,我们看到在从ATM机取175美元时会发生什么。

代码实现:

下图演示了紧耦合与松耦合之间的区别。

以Vespe的实现为参考实现一个简单的事件系统。下面是该系统的UML类图。

class Event:

    def __init__(self, name):
        self.name = name

    def __str__(self):
        return self.name


class Widget:

    def __init__(self, parent=None):
        self.parent = parent

    def handle(self, event):
        handler = 'handle_{}'.format(event)
        if hasattr(self, handler):
            method = getattr(self, handler)
            method(event)
        elif self.parent:
            self.parent.handle(event)
        elif hasattr(self, 'handle_default'):
            self.handle_default(event)


class MainWindow(Widget):

    def handle_close(self, event):
        print('MainWindow: {}'.format(event))

    def handle_default(self, event):
        print('MainWindow Default: {}'.format(event))


class SendDialog(Widget):

    def handle_paint(self, event):
        print('SendDialog: {}'.format(event))


class MsgText(Widget):

    def handle_down(self, event):
        print('MsgText: {}'.format(event))


def main():
    mw = MainWindow()
    sd = SendDialog(mw)
    msg = MsgText(sd)

    for e in ('down', 'paint', 'unhandled', 'close'):
        evt = Event(e)
        print('\nSending event -{}- to MainWindow'.format(evt))
        mw.handle(evt)
        print('Sending event -{}- to SendDialog'.format(evt))
        sd.handle(evt)
        print('Sending event -{}- to MsgText'.format(evt))
        msg.handle(evt)

if __name__ == '__main__':
    main()

在无法预先知道处理程序的数量和类型时,该模式有助于对请求/处理事件进行建模。适合使用责任链模式的系统例子包括基于事件的系统、采购系统和运输系统。

在责任链模式中,发送方可直接访问链中的首个节点。若首个节点不能处理请求,则转发给下一个节点,如此直到请求被某个节点处理或者整个链遍历结束。这种设计用于实现发送方与接收方(多个)之间的解耦。

Share this Post

说点什么

avatar
  Subscribe  
提醒