当前位置: 首页 > 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,这是因为它们每条消息只输出一行。

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

相关文章:

  • DeepSeek 赋能自然语言处理:从理论到实践的全方位解析
  • Qt指南针
  • 支持selenium的chrome driver更新到136.0.7103.49
  • 打包 Python 项目为 Windows 可执行文件:高效部署指南
  • 33、VS中提示“以下文件中的行尾不一致。是否将行尾标准化?“是什么意思?
  • 【C语言练习】014. 使用数组作为函数参数
  • Java关键字解析
  • Canvas特效实例:黑客帝国-字母矩阵(字母雨)
  • OpenAI最新发布的GPT-4.1系列模型,性能体验如何?
  • 设计模式简述(十四)组合模式
  • Unity SpriteMask(精灵遮罩)
  • Go 语言中一个功能强大且广泛使用的数据验证库github.com/go-playground/validator/v10
  • Js扩展DOM、BOM、AJAX、事件、定时器
  • 系统架构设计师:设计模式概述
  • 为 Unity 项目添加自定义 USB HID 设备支持 (适用于 PC 和 Android/VR)-任何手柄、无人机手柄、摇杆、方向盘
  • 补题( Convolution, 二维卷积求输出矩阵元素和最大值)
  • 华为云Astro大屏连接器创建操作实例:抽取物联网iotda影子设备数据的连接器创建
  • 【中间件】bthread_基础_TaskControl
  • Kotlin革新数据分析
  • linux 使用nginx部署next.js项目,并使用pm2守护进程
  • 阿根廷发生5.6级地震,震源深度30公里
  • 大学2025丨对话深大人工智能学院负责人李坚强:产学研生态比“造天才”更重要
  • “80后”蒋美华任辽宁阜新市副市长
  • 云南铁路:打造“铁路+金融+产业”融合发展生态
  • 解放日报:中国大模型企业的发展机遇已经到来
  • 豆神教育:2024年净利润1.37亿元,同比增长334%