python 实现 责任链模式
本文的目录地址
本文的代码地址
开发一个应用时,多数时候我们都能预先知道哪个方法能处理某个特定请求。然而,情况并非总是如此。例如,在广播计算机网络中,会将请求发送给所有节点,但仅对所发送内容感兴趣的节点会处理请求。
如果一个节点对某个请求不感兴趣或者不知道该如何处理这个请求,可以执行以下两个操作。
- 忽略这个请求,什么都不做
- 将请求转发给下一个节点
节点对一个请求的反应方式是实现的细节。然而,我们可以使用广播计算机网络来类比理解责任链模式是什么。责任链(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 实现 责任链模式相关推荐
- python责任链模式
责任链模式是一种设计模式.在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知道链上的哪一个对象最 ...
- 设计模式之五 责任链模式(Chain of Responsibility)
2019独角兽企业重金招聘Python工程师标准>>> 一. 场景 相信我们都有过这样的经历: 我们去职能部门办理一个事情,先去了A部门,到了地方被告知这件事情由B部门处理: 当我们 ...
- Python设计模式-职责链模式
Python设计模式-职责链模式 代码基于3.5.2,代码如下; #coding:utf-8 #职责链模式class Handler():def __init__(self):self.success ...
- 最近学习了责任链模式
2019独角兽企业重金招聘Python工程师标准>>> 前言 来菜鸟这个大家庭10个月了,总得来说比较融入了环境,同时在忙碌的工作中也深感技术积累不够,在优秀的人身边工作必须更加花时 ...
- 《JAVA与模式》之责任链模式
2019独角兽企业重金招聘Python工程师标准>>> 详细请访问原博客:http://www.cnblogs.com/java-my-life/archive/2012/05/28 ...
- 责任链模式 和观察者模式
2019独角兽企业重金招聘Python工程师标准>>> 责任链模式平常没怎么用过,今天看到了责任链模式的基本构成.大体就是把一件事情分给n个互相有引用的类去执行.比如解析ip地址.过 ...
- 设计模式--责任链模式
2019独角兽企业重金招聘Python工程师标准>>> 责任链模式(chain of responsibility): 有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链 ...
- 轻松学习Java设计模式之责任链模式
我们的态度是:每天进步一点点,理想终会被实现. 前言 设计模式,可能很多人都是看到代码知道怎么回事,但是离开代码再让其说出来,估计就有点含糊其词了,包括我自己在内.Android中其实用到的设计模式也 ...
- Spring中如何使用责任链模式
2019独角兽企业重金招聘Python工程师标准>>> 关于责任链模式,其有两种形式,一种是通过外部调用的方式对链的各个节点调用进行控制,从而进行链的各个节点之间的切换:另一种是链的 ...
- Chain of Responsibility 责任链模式 MD
责任链模式 简介 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链,请求在这个链上[传递],直到链上的某一个对象决定处理此请求.发出这个请求的客户 ...
最新文章
- (未完)httpd进程数查询,prefork模式修改apache最大连接数
- DC使用教程系列1-.synopsys.dc.setup的建立
- zabbix4.2 系列(二):agent配置
- Linux as4开启telnet,linux as4 虚拟机 上开启 telnet 和ssh 和 ftp 服务
- 快捷键jdeveloper
- 冠军奖 3 万元!CSDN×易观算法大赛火热进行中
- 有人说JavaScript是未来的编程语言?这是为什么?
- python自动测试m_python自动化测试实例解析
- 面试再问HashMap,求你把这篇文章发给他!
- TRC文件转ASC文件
- Excel使用频率较高的数据处理和分析-----数据透视表
- 什么是电子邮件地址?
- ST-GCN demo运行记录
- 数据挖掘算法之FP-Growth算法介绍及Spark代码实现
- Python VLC+PyQt5 读取视频音频流
- 前端HTML5 颜色选择器 input[type = color]
- Vue的@click、@click.prevent、@click.stop
- 单位共享上网sygate代理服务软件完全解决方案
- error MSB8020: 无法找到 v142 的生成工具(平台工具集 =“v142”)。若要使用 v142 生成工具进行生成,请安装 v142 生成工具。
- python抢券代码_抢券抢不到生气了,准备写一个自动抢券的东东,时间成本最低的 web 方案是什么?...