python与网页设计的区别_Python与设计模式(三):行为型模式(上)

接前文:kant li:Python与设计模式(二):结构型模式(下)​zhuanlan.zhihu.com

行为型模式主要处理对象间的通信问题,包括责任链模式、命令模式、解释器模式、迭代器模式、观察者模式、状态模式、策略模式、模板模式等。

1. 责任链模式

责任链模式一般用于任务的链式处理。前一个处理者处理后,任务传递给下一个处理者,直至完成。

大家常用的例子是OA系统中的审批流程,比如请假。假设3天以下的假期只需要团队长审批,3天以上的同时需要部门经理审批,7天以上的还需要业务总监审批,那么,就形成了一条请假审批的责任链:主管审批之后,任务没有完成,提交至经理,如果还没有完成,则继续往上级提交。

一般的代码会为每一个审批级构建一个类,定义它的处理方法和下一个处理者:

class Director:

successor = None

def handle_vocation(self, days): pass

class Manager:

successor = Director()

def handle_vocation(self, days):

if days < 7:

pass

else:

self.successor.handle_vocation(days)

class Teamleader:

successor = Manager()

def handle_vocation(self, days):

if days < 3:

pass

else:

self.successor.handle_vocation(days)

作为例子,我们可以通过这个代码大概理解责任链模式的含义。通过责任链模式,我们解耦了请求发起者和请求处理者之间的关系,请假的人不需要关心谁来审批的问题,只需要把假条给他的直接主管。

但我们都知道,现实中应该不会这么写代码。今天审批请假,明天审批出差,后天审批报销,不同层级的人走的审批路线还不一样,这样的类和方法是写不完的,缺乏灵活性。

我们看钉钉的设计,可以由行政部门根据需要,动态设计审批流程,不同岗位、不同部门、不同层级的员工对应不同的流程,这才是比较贴合实际的情形,我们一般也会这么写。

class Process:

id = 0

name = ''

class Step:

id = 0

name = ''

process_id = 0

pre_step_id = 0

next_step_id = 0

即有一个流程对象,每个流程对象有不同的步骤,每个步骤有前置步骤和后续步骤,这里使用id来表示,其实是对应着实际中的数据库记录。可以每完成一个步骤,就生成下一个步骤,也可以在任务一开始就生成所有步骤。

仔细想想,这应该只是处理实际需求中的责任链模式,而不是在代码的组织中体现了责任链模式,可供参考吧。毕竟,需要硬编码写死的责任链还是比较少的。

2. 命令模式

命令模式的目的也是解耦请求发起者和请求处理者之间的关系。方式是把请求(或者说命令)做单独的封装,通过请求的执行方法来调用处理者完成任务。

常用的例子是餐馆点餐:不同的厨师负责不同的菜品,服务员需要根据客户点的菜,将请求发给不同的厨师。通过命令模式,服务员不需要知道哪个厨师负责哪个菜品,相关信息保存在对应菜品(即请求,或者说命令)的信息中,调用执行方法时,将自动通知对应的厨师完成菜品。

因为请求单独做了封装,所以可以保存在一个队列之类的容器中,也可以随时撤销。

有些不需要马上完成的工作,打包成命令,放入某个队列,等处理者有空的时候再执行是很合理的。比如一些服务器维护、数据库备份命令等,我们一般设置定时任务来进行处理,有时会设置在某个预计访问量比较少的时间段,但这个时间段并不总是可靠的,那么,就可以先放入任务队列中。如果CPU占用率、硬盘读写量低于设定值,就让命令执行,否则就放回队列继续等待。

import abc

class Requester:

def __init__(self):

self._commands = []

def add_command(self, command):

self._commands.append(command)

def send_commands(self):

for command in self._commands:

command.execute()

class Command(metaclass=abc.ABCMeta):

def __init__(self, receiver):

self._receiver = receiver

@abc.abstractmethod

def execute(self):

pass

class Command_1(Command):

def execute(self):

self._receiver.action()

class Receiver:

def action(self):

pass

def main():

receiver = Receiver()

command_1 = Command_1()

requester = Requester()

requester.add_command(command_1)

requester.send_commands()

if __name__ == "__main__":

main()

3. 观察者模式

与责任链模式、命令模式一样,观察者模式也用于处理消息发送者和接收者之间的关系。

不同的是:责任链模式下,发送者只需要知道第一个消息接收者就行,消息在一个个接收者之间链式传播;

命令模式下,消息发送者只需要了解有什么命令,至于命令要传给谁执行,则由命令自身决定;

而在观察者模式下,消息发送者把接收者保存在一个列表中,当自身状态发生改变,就通知列表中的所有成员。

Python 主流 Web 框架 Django 有一个第三方包,django-observer,就提供了跟踪模型字段变化的简洁方式,用户可以注册回调函数,在字段变化时自动执行一些任务。

被观察者通知观察者,可以同步通知,即直接调用一些函数;也可以通过消息队列进行异步通知,这样,被观察者就不用等待观察者的反馈,直接进行自己的下一步任务。

就通知消息来说,可以将准确的变动信息直接告知接收者,即所谓的“push”模式,也可以只告知发生变动,让消息接收者根据需要拉取信息,即所谓的“pull”模式。

Python中的观察者模式没什么特殊的,但是可以通过属性设置器在类属性变动时触发通知动作。简单示例如下:

class Notifier:

def __init__(self):

self._observers = set()

self._state = None

def add_observer(self, observer):

self._observers.add(observer)

def remove_boserver(self, observer):

self._observers.discard(observer)

def _notify(self):

for observer in self._observers:

observer.update(self.state)

@property

def state(self):

return self._state

@state.setter

def state(self, obj_state):

self._state = obj_state

self._notify()

4. 状态模式

有限状态机是现实中常见的场景:当对象处于不同状态时,执行不同的行为;或者当对象的状态发生变化时,执行特定的行为。

常见的例子是零食贩卖机:当我们塞入零钱时,达到某些零食的价格,可能对应零食的指示灯就会变绿,在这种状态下,我们可以正常购买,而有些零食可能价格较贵,指示灯还是红色的,点击购买时会给出余额不足的提示。

在代码中,实现状态模式,一般要关注两点,一个是状态变化时需要执行的动作,一个是处在不同状态时,对象会表现出不同的行为。

简单代码体现如下:

class VenderMachine:

def set_state(self, state):

do_something()

self._state = state

def execute(self):

self._state.execute()

class State_A:

def execute(self): pass

class State_B:

def execute(self): pass

vender_machine = VenderMachine()

state_a = State_A()

vender_machine.set_state(state_a)

vender_machine.execute()

在Python中,很多第三方库提供了状态机的简单实现,目前,GitHub 上 Star 最多的应该是 transition 模块(https://github.com/pytransitions/transitions),有兴趣可以直接参考文档,还是挺有意思的。

未完待续……

公众号:ReadingPython

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/435017.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IP保留地址

IP地址是IP网络中数据传输的依据&#xff0c;它标识了IP网络中的一个连接&#xff0c;一台主机可以有多个IP地址。IP分组中的IP地址在网络传输中是保持不变的。   1.基本地址格式   现在的IP网络使用32位地址&#xff0c;以点分十进制表示&#xff0c;如172.16.0.0。地址格式…

影像拼接(3种方法)

1、镶嵌 2、镶嵌至新栅格 3、envi无缝拼接(相对arcgis时间上更长)

读取Excel文件数据

1.用APP直接读取Excel文件 这种方法原理是用APP打开EXCEL文件&#xff0c;操作单元格读取数据&#xff0c;快速比较慢&#xff0c;基本不采用这种方式。 2.用APP把Excel文件转成Txt文件&#xff0c;再读取Txt文件 过程: a. Microsoft.Office.Interop.Excel.Worksheet SAVE 方法…

python监听多个udp端口_Python的Socket编程过程中实现UDP端口复用的实例分享

关于端口复用一个套接字不能同时绑定多个端口&#xff0c;如果客户端想绑定端口号&#xff0c;一定要调用发送信息函数之前绑定( bind )端口&#xff0c;因为在发送信息函数( sendto, 或 write )&#xff0c;系统会自动给当前网络程序分配一个随机端口号&#xff0c;这相当于随…

Android系统的开机画面显示过程分析

提到Android系统的UI&#xff0c;我们最先接触到的便是系统在启动过程中所出现的画面了。Android系统在启动的过程中&#xff0c;最多可以出现三个画面&#xff0c;每一个画面都用来描述一个不同的启动阶段。本文将详细分析这三个开机画面的显示过程&#xff0c;以便可以开启我…

arcgis报错常用解决方法

1.输出路径不要改动&#xff0c;选择arcgis默认的数据库&#xff0c;运行完后再将数据导出一份 2.输出文件名以字母开头&#xff08;个人尝试有时候数字开头会报错&#xff09; 3.确保自己路径中没有中文 4.再次运行工具箱&#xff0c;第一次运行的时候可能程序调用会出错 …

windows和linux的内存管理

windows的内存管理很是严谨&#xff0c;使用内存必须首先分配&#xff0c;当然每个操作系统都是这样&#xff0c;然而windows的严谨在于分配的过程&#xff0c;分为保留和提交两个阶段&#xff0c;其中保留的含义就是在进程的虚拟地址空间保留一块空间&#xff0c;不能用作他用…

python垃圾邮件识别_【Python】垃圾邮件识别

下载W3Cschool手机App&#xff0c;0基础随时随地学编程导语利用简单的机器学习算法实现垃圾邮件识别。让我们愉快地开始吧~相关文件密码: qa49数据集源于网络&#xff0c;侵歉删。开发工具Python版本&#xff1a;3.6.4相关模块&#xff1a;scikit-learn模块&#xff1b;jieba模…

修改Linux内核的启动Logo和禁用启动光标

Linux内核下使用的图片文件类型是pnm和PPm格式的&#xff0c;所以在开始介绍修改linux内核启动LOGO之前&#xff0c; 1&#xff0c;先需要介绍一下怎么样设计自己开始logo的ppm图片&#xff0c;首先选择一张png格式的图片 使用如下命令确保你必须安装以下的工具(pngtopnm,pnmqu…

JavaScript 判断浏览器类型

var Sys {}; var ua navigator.userAgent.toLowerCase(); var s; (s ua.match(/msie ([\d.])/)) ? Sys.ie s[1] : (s ua.match(/firefox\/([\d.])/)) ? Sys.firefox s[1] : (s ua.match(/chrome\/([\d.])/)) ? Sys.chrome s[1] : (s ua.match(/opera.(…

python time perf_Python Time 的学习笔记

PyNotes-timePyNotes(2)关于time的简单介绍参考资料概述time模块 时间戳的获取、时间格式的转换和程序运行时间的计算。方法时间的获取time.time()以floa浮点数获取当前时间戳&#xff0c;即计算机内部时间值&#xff0c;epoch 是1970年1月1日00:00:00(UTC)>>> time.t…

Linux logo和屏幕光标

logo和屏幕光标 Linux默认开机LOGO一般都是80x80的小企鹅图标&#xff0c;有时候为了一些效果&#xff0c;希望在Linux 启动过程中&#xff0c;全屏看到用户自定义的LOGO&#xff0c;这就需要为Linux增加新的LOGO。 准备png图片 使用任何图片软件&#xff0c;制作一张自定义…

arcgis选出点规定范围的面

示例数据如下 对点数据进行缓冲区建立 打开缓冲区工具箱 主要设置输入数据和距离&#xff08;缓冲范围&#xff09; 缓冲结果如下 接下来进行空间连接 输入目标要素&#xff08;选出的面&#xff09;和连接要素&#xff08;缓冲的结果&#xff09; 打开空间连接的属性表 选中我…

函数实现-aoti-atol

1. 函数原型 int atoi ( const char * str ); long int atol ( const char * str ); 2. 函数工作 atoi是将字符串转化为整型&#xff0c;atol是将字符串转化为长整型&#xff0c;这两个函数的实现十分相似。工作步骤基本如下&#xff1a; 跳过若干空格、制表符等 如果有…

python2卸载后yum不可用_centos7误删除python2导致的python和yum不可用处理-阿里云开发者社区...

centos7查看版本cat /etc/redhat-release // 我这边是 CentOS Linux release 7.6.1810 (Core)强制删除已安装程序及其关联rpm -qa|grep python|xargs rpm -ev --allmatches --nodeps删除所有残余文件 ##xargs,允许你对输出执行其他某些命令whereis python |xargs rm -frv验证删…

arcgis批量按掩膜提取栅格

新建工具箱 迭代要素类 插入栅格

SIP协议学习1

SIP协议是由IETF提出的在IP网络上进行多媒体通信的应用层控制协议。采用分层的方法来创建服务&#xff0c;是应用层上的一个控制协议&#xff0c;用来创建&#xff0c;修改和终止有多个参与者的多媒体会话进程。参与会话的成员可以通过组播&#xff0c;单播或者两者结合的方式进…

一些关于罗马字符的知识

I 1 V 5 X 10 L 50 C 100 D 500 M 1000 下面是关于构造罗马数字的一些通用的规则的介绍&#xff1a; 字符是叠加的。I 表示 1&#xff0c;II 表示 2&#xff0c;而 III 表示 3。VI 表示 6 (字面上为逐字符相加&#xff0c;“5 加 1”)&#xff0c;VII 表示 7&#xff0c…

python 分词 识别_python分词如何实现新词识别

2013-12-19 回答# -*- coding: utf-8 -*-import jiebacreated on 2015-11-23def word_split(text):"""split a text in words. returns a list of tuple that contains(word, location) location is the starting byte position of the word."""…