本文的目录地址

本文的代码地址

开发一个应用时,多数时候我们都能预先知道哪个方法能处理某个特定请求。然而,情况并非总是如此。例如,在广播计算机网络中,会将请求发送给所有节点,但仅对所发送内容感兴趣的节点会处理请求。

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

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

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

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

软件的例子

Java的servlet过滤器是在一个HTTP请求到达目标处理程序之前执行的一些代码片段。在使用servlet过滤器时,有一个过滤器链,其中每个过滤器执行一个不同动作(用户身份验证、记日志、数据压缩等),并且将请求转发给下一个过滤器知道链结束;如果发生错误(例如,连续三次身份验证失败)则跳出处理流程。

Apple的Cocoa和Cocoa Touch框架使用责任链来处理事件。在某个视图接收到一个其并不知道如何处理的事件时,会将事件转发给其超视图,直到有个视图能够处理这个事件或者视图链结束。

应用案例

通过使用责任链模式,我们能让许多不同对象来处理一个特定请求。在我们预先不知道应该由哪个对象来处理请求时,这是有用的。其中一个例子是采购系统。在采购系统中,有许多核准权限。某个核准权限可以核准在一定额度之内的订单,假设为100美元。如果订单超过了100美元,则会将订单发送给链中的下一个核准权限,比如能够核准在200美元以下的订单,等等。

另一个责任链例子,单个事件,比如一次鼠标点击,可被多个事件监听者捕获。

不过应该注意,如果所有请求都能被单个处理程序处理,责任链就没用了,除非确实不知道会是哪个程序处理请求。这一模式的价值在于解耦。客户端与所有处理程序之间不再是多对多的关系,客户端仅需要知道如何与链的起始节点进行通信。

实现

这里将会实现一个简单的事件系统。下面是该系统的UML类图。

Event类描述一个事件。为了让它简单一点,在我们的案例中一个事件只有一个name属性。

class Event:def __init__(self,name):self.name=namedef __str__(self):return self.name

Widget类是应用的核心类。UML图中展示的parent聚合关系表明每个控件都有一个到父对象的引用。按照约定,我们假设父对象是一个Widget实例。

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

handle()方法使用动态分发,通过hasattr()和getattr()决定一个特定请求(event)应该由谁来处理。如果被请求处理事件的控件并不支持该事件,则有两种回退机制。如果控件有parent,则执行parent的handle()方法。如果控件没有parent,但有handle_default()方法,则执行handle_default()方法。

    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)

此时,你可能已明白为什么UML类图中Widget和Event类仅是关联关系而已(不是聚合或组合关系)。关联关系用于表明Widget类知道Event类,但对其没有任何严格的引用,因为事件仅需要作为参数传递给handle()。

MainWindow、MsgText和SendDialog是具有不同行为的控件。我们并不期望这三个控件都能处理相同的事件,即使它们能处理相同事件,表现出来也可能是不同的。MainWindow仅能处理close和default事件。

class MainWidow(Widget):def handle_close(self,event):print('MainWindow: {}'.format(event))def handle_default(self,event):print('MainWindow: {}'.format(event))

SendDialog仅能处理paint事件。

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

最后,MsgText只能处理down事件。

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

main()函数展示如何创建一些控件和事件,以及控件如何对那些事件做出反应。所有事件都会被发送给所有控件。注意其中每个控件的父子关系。sd对象(SendDialog的一个实例)的父对象是mw(MainWindow的一个实例)。然而,并不是所有对象都需要一个MainWindow实例的父对象。例如,msg对象是以sd作为父对象。

def main():mw=MainWidow()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)

完整代码文件chain.py,运行结果如下

Sending event -down- to MainWindow
MainWindow: down
Sending event -down- to SendDialog
MainWindow: down
Sending event -down- to MsgText
MsgText: downSending event -paint- to MainWindow
MainWindow: paint
Sending event -paint- to SendDialog
SendDialog: paint
Sending event -paint- to MsgText
SendDialog: paintSending event -unhandled- to MainWindow
MainWindow: unhandled
Sending event -unhandled- to SendDialog
MainWindow: unhandled
Sending event -unhandled- to MsgText
MainWindow: unhandledSending event -close- to MainWindow
MainWindow: close
Sending event -close- to SendDialog
MainWindow: close
Sending event -close- to MsgText
MainWindow: close

从输出中我们能看到一些有趣的东西。例如,发送一个down事件给MainWindow,最终被MainWindow默认处理函数处理。另一个不错的用例是,虽然close事件不能被SendDialog和MsgText直接处理,但所有close事件最终都能被MainWindow正确处理。这正是使用父子关系作为一种回退机制的优美之处。

python 实现 责任链模式相关推荐

  1. python责任链模式

    责任链模式是一种设计模式.在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知道链上的哪一个对象最 ...

  2. 设计模式之五 责任链模式(Chain of Responsibility)

    2019独角兽企业重金招聘Python工程师标准>>> 一. 场景 相信我们都有过这样的经历: 我们去职能部门办理一个事情,先去了A部门,到了地方被告知这件事情由B部门处理: 当我们 ...

  3. Python设计模式-职责链模式

    Python设计模式-职责链模式 代码基于3.5.2,代码如下; #coding:utf-8 #职责链模式class Handler():def __init__(self):self.success ...

  4. 最近学习了责任链模式

    2019独角兽企业重金招聘Python工程师标准>>> 前言 来菜鸟这个大家庭10个月了,总得来说比较融入了环境,同时在忙碌的工作中也深感技术积累不够,在优秀的人身边工作必须更加花时 ...

  5. 《JAVA与模式》之责任链模式

    2019独角兽企业重金招聘Python工程师标准>>> 详细请访问原博客:http://www.cnblogs.com/java-my-life/archive/2012/05/28 ...

  6. 责任链模式 和观察者模式

    2019独角兽企业重金招聘Python工程师标准>>> 责任链模式平常没怎么用过,今天看到了责任链模式的基本构成.大体就是把一件事情分给n个互相有引用的类去执行.比如解析ip地址.过 ...

  7. 设计模式--责任链模式

    2019独角兽企业重金招聘Python工程师标准>>> 责任链模式(chain of responsibility): 有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链 ...

  8. 轻松学习Java设计模式之责任链模式

    我们的态度是:每天进步一点点,理想终会被实现. 前言 设计模式,可能很多人都是看到代码知道怎么回事,但是离开代码再让其说出来,估计就有点含糊其词了,包括我自己在内.Android中其实用到的设计模式也 ...

  9. Spring中如何使用责任链模式

    2019独角兽企业重金招聘Python工程师标准>>> 关于责任链模式,其有两种形式,一种是通过外部调用的方式对链的各个节点调用进行控制,从而进行链的各个节点之间的切换:另一种是链的 ...

  10. Chain of Responsibility 责任链模式 MD

    责任链模式 简介 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链,请求在这个链上[传递],直到链上的某一个对象决定处理此请求.发出这个请求的客户 ...

最新文章

  1. (未完)httpd进程数查询,prefork模式修改apache最大连接数
  2. DC使用教程系列1-.synopsys.dc.setup的建立
  3. zabbix4.2 系列(二):agent配置
  4. Linux as4开启telnet,linux as4 虚拟机 上开启 telnet 和ssh 和 ftp 服务
  5. 快捷键jdeveloper
  6. 冠军奖 3 万元!CSDN×易观算法大赛火热进行中
  7. 有人说JavaScript是未来的编程语言?这是为什么?
  8. python自动测试m_python自动化测试实例解析
  9. 面试再问HashMap,求你把这篇文章发给他!
  10. TRC文件转ASC文件
  11. Excel使用频率较高的数据处理和分析-----数据透视表
  12. 什么是电子邮件地址?
  13. ST-GCN demo运行记录
  14. 数据挖掘算法之FP-Growth算法介绍及Spark代码实现
  15. Python VLC+PyQt5 读取视频音频流
  16. 前端HTML5 颜色选择器 input[type = color]
  17. Vue的@click、@click.prevent、@click.stop
  18. 单位共享上网sygate代理服务软件完全解决方案
  19. error MSB8020: 无法找到 v142 的生成工具(平台工具集 =“v142”)。若要使用 v142 生成工具进行生成,请安装 v142 生成工具。
  20. python抢券代码_抢券抢不到生气了,准备写一个自动抢券的东东,时间成本最低的 web 方案是什么?...

热门文章

  1. python写一个地球同步卫星图动态壁纸(第一部分)
  2. qqxml卡片 php代码,qqxml卡
  3. easyexcel 无模板写入_EasyExcel模板填充踩坑
  4. verilog学习笔记——8位数码管驱动设计与验证
  5. 电子公文流转暨无纸办公系统
  6. 分盘后磁盘空间不够,用分区助手增加某个磁盘空间
  7. 入手华为云学生机体验
  8. gm21模型python_GM11灰色模型
  9. sql server的增删改查语句
  10. 《ERP原理》期末复习——第一章 初识ERP(企业资源计划)