当前位置: 首页 > news >正文

Python Cookbook-6.14 实现状态设计模式

任务

你希望你程序中的某个对象能在不同的“状态”之间切换,而且该对象的行为方式也能随着状态的变化而变化。

解决方案

状态设计模式的关键思路是将“状态”(带有它自身的行为方式)对象化,使其成为一个类实例(带有一些方法)。在Python中,你不用创建一个抽象类来表现这些不同状态共同的接口:只需为这些“状态”本身编写不同的类即可。比如:

class TraceNormal(object):'正常的状态'def startMessage(self):self.nstr = self.characters = 0def emitString(self,s):self.nstr += 1self.characters += len(s)def endMessage(self):print '%d characters in %d strings' %(self.characters,self.nstr)
class TraceChatty(object):'详细的状态'def startMessage(self):self.msg = []def emitstring(self,s):self.msg.append(repr(s))def endMessage(self):print 'Message:', ','.join(self.msg)
class TraceQuiet(object):'无输出的状态'def startMessage(self):passdef emitString(self,s):passdef endMessage(self):pass
class Tracer(object):def __init__(self,state):self.state = statedef setState(self,state):self.state = statedef emitStrings(self,strings):self.state.startMessage()for s in strings:self.state.emitString(s)self.state.endMessaqe()
if __name__ == '__main__':t = Tracer(TraceNormal())t.emitStrings('some example strings here'.split())
#输出:21 characters in 4 stringst.setstate(TraceQuiet())t.emitStrings('some example strings here'.split())
#无输出t.setstate(TraceChatty())t.emitStrings('some example strings here'.split())
#输出:Message:'some','example','strings','here'

讨论

通过状态设计模式,我们能够“发掘出”一个对象的一些相关的行为(还可能包括一些与这些行为相关的数据),并将其置入一个辅助的状态对象,然后主对象可以在需要的时候通过调用“状态”对象的方法委托给这些行为。在Python 的术语中,这种设计模式和重新绑定整个对象的__class__惯用法有一些联系,详情请参看6.11节,和重新绑定某些方法的方式也有些关联(如2.14节所示)。从某种意义上说,状态设计模式是处于前两种概念之间的:你将一些关联的行为组织起来,而不是通过更改对象的__class__ 在这些行为之间切换,也不是修改每一个方法。如果用经典设计模式的术语来描述,本节提供的模式处于经典状态设计模式和经典策略设计模式之间。

与一些相关的 Python 概念相比,状态设计模式看上去更有魅力,因为适当数量的数据可以和你要委托的行为共生,而且数量正合适,正好可用于支持每种特别的行为。在本节解决方案的例子中,不同的状态对象需要截然不同的数据类型和不同数量的数据:对于类 TraceQuiet 而言,根本就无须任何数据,而 TraceNormal 只需要几个数字,TraceChatty 则需要所有的字符串列表。这些责任通常都被主对象委托给了各个“状态对象”。

不过有时会有一些超出我们的示例的情况,状态对象可能会需要更紧密地同主对象合作在某些环境下甚至还需要调用主对象的方法,访问主对象的属性。为了实现这个目的,主对象可以传递一个参数给“状态”对象,可以是self或者某个self的被绑定方法。比如,假设本节解决方案中的示例需要扩展功能,主对象必须记录它送出的消息已经输出了多少行。Tracer.__init__必须给每个实例增加一个新的初始化项self.lines=0,而“状态”对象的 endMessage方法的签名也需要被扩展为 defendMessage(self,tracer):。不过在类TraceQuiet的 endMessage 中会忽略掉这个tacer 参数,因为它从来不用输出任何行;其他两个类的实现则需要增加一行声明 tracer.lines +=1,这是因为它们每条消息只输出一行。

如你所见,这种额外新增的功能要求更紧密的联络,但并不是什么难对付的问题。具体地说,经典状态设计模式的关键特性是,状态切换由状态对象掌握(而在策略设计模式中,切换则来自外部),不过这并不是区分两种设计模式的关键。

http://www.xdnf.cn/news/244729.html

相关文章:

  • Windows下Python3脚本传到Linux下./example.py执行失败
  • 3D版同步帧游戏
  • 案例:自动化获取Web页面小说(没钱修什么仙)——selenium
  • mem0 安装与测试:一个强大的对话记忆管理工具
  • 机器人手臂控制器:EMC电磁兼容解决(一)
  • 分寝室(C++完成)
  • 阿里云自动备份网站,阿里云自动备份网站的方法
  • kotlin中 热流 vs 冷流 的本质区别
  • 编程语言全景解析与编程技巧深度探索
  • 基于MyBatis的银行转账系统开发实战:从环境搭建到动态代理实现
  • 人工智能——DBSCAN 聚类算法
  • Webug4.0靶场通关笔记07- 第9关反射XSS和第10关存储XSS
  • 【Quest开发】极简版!透视环境下抠出身体并能遮挡身体上的服装
  • 免费实用的图像处理工具箱​
  • Java 泛型参数问题:‘ResponseData.this‘ cannot be referenced from a static contex
  • 原型模式(Prototype Pattern)详解
  • K8S - ReplicaSet 与 Deployment 深度解析与实战
  • Curl 全面使用指南
  • 【含文档+PPT+源码】基于大数据的交通流量预测系统
  • WebStorm用户界面
  • 【排序算法】八大经典排序算法详解
  • Wireshark抓取SMTP协议报文
  • 算法查找目录
  • Webug4.0靶场通关笔记08- 第11关万能密码登录(SQL注入漏洞)
  • Linux之shell脚本
  • Golang多人在线坦克对战游戏(帧同步)
  • Android Kotlin 项目集成 Firebase Cloud Messaging (FCM) 全攻略
  • 多模态大语言模型arxiv论文略读(五十三)
  • 红利底波是什么意思?
  • WPF处理大规模激光数据计算与安全传输处理