状态设计模式

#状态设计模式

行为模式关注的是对象的相应性。它们通过对象之间的交互以实现更强大的功能。状态设计模式是一种行为设计模式,有时也被称为状态模式的对象。在此模式中,一个对象可以基于其内部状态封装多个行为。状态模式也可以看作是在运行时改变对象行为的一种方式。

以收音机为例,收音机具有AM/FM(切换开关)两种调频方式和一个扫描按钮,该按钮可扫描多个FM/AM频道。当用户打开无线电时,收音机的基本状态已经设置好了(例如,它被设置为FM)。通过单击扫描按钮,可以将收音机调谐到多个有效的FM频率或频道。然后,当基本状态改为AM时,扫描按钮则会帮助用户调谐到多个AM频道。因此,根据收音机的基本状态(AM/FM),当调谐到AM或FM状态时,扫描按钮的行为就会动态地改变。

因此,状态模式允许对象在其内部状态变化时改变其行为。这看起来就像对象本身已经改变了它的类一样。状态设计模式常用于开发有限状态机,并帮助协调状态处理操作。

##一、理解状态设计模式

状态设计模式在3个主要参与者的协助下工作:
(1)State:这被认为是封装对象行为的接口。这个行为与对象的状态相关联。
(2)ConcreteState:这是实现State接口的子类。ConcreteState实现与对象的特定状态相关联的实际行为。
(3)Context:这定义了客户感兴趣的接口。Context还维护一个ConcreteState子类的实例,该子类在内部定义了对象的特定状态的实现。

在这个例子中,我们定义了一个具有Handle()抽象方法的状态接口。ConcreteState类,ConcreteStateA和ConcreteStateB用于实现状态接口,同时,定义的Handle()方法是特定与ConcreteState类。因此,当Context类被设置为一个状态时,该状态的Concrete类的Handle()方法就会被调用。在以下实例中,由于Context设置为stateA,因此将调用ConcreteStateA.Handle()方法。

from abc import ABCMeta, abstractmethod

class State(metaclass = ABCMeta):
	@abstractmethod
	def Handle(self):
		pass
class ConcreteStateA(State):		
	def Handle(self):
		print('ConcreteStateA')
class ConcreteStateB(State):		
	def Handle(self):
		print('ConcreteStateB')	
class Context(State):		
	def __init__(self):
		self.state = None
	def getState(self):	
		return self.state
	def setState(self, state):
		self.state = state
	###	
	def Handle(self):
		self.state.Handle()	
		
if __name__ == '__main__':		
	context = Context()
	stateA = ConcreteStateA()
	stateB = ConcreteStateB()
	context.setState(stateA)	##
	context.Handle()

##二、UML图
这里写图片描述

UML图的组成元素:

  • State:这是一个定义了Handle()抽象方法的接口。Handle()方法需要通过ConcreteState类来实现。
  • ConcreteState:实现Handle()方法并可以根据状态的变化定义要采取的实际行动。
  • Context:这是一个接收客户端请求的类。它维护着对象的当前状态的引用。这样,可以根据相应的请求,来调用具体的行为了。

假设要用一个简单的按钮来实现电视遥控器,执行开/关动作。如果电视打开,这个遥控器按钮将关闭电视,反之亦然。在这种情况下,State接口将会定义相应的方法来执行诸如打开/关闭电视等操作。我们还需要定义Concrete类来处理不同的状态。在这个例子中,我们有两个主要状态,StartState和StopState,它们分别表示电视的打开状态和关闭状态。
就本例来说,TVContext类将实现State接口并维护对当前状态的引用。根据相应的请求,TVContext将它们转发到相应的ConcreteState类,这个类实现了(针对给定状态的)实际行为,从而执行所需的操作。因此,在这种情况下,基本状态是StartState(如前面定义的),TVContext类接收的请求是关闭但是。TVContext类可以理解该需求,并相应地将它转发到StopState相应的类,之后这个类就会从内部调用doThis()方法来实际关闭电视。

from abc import ABCMeta, abstractmethod
class State(metaclass = ABCMeta):
	@abstractmethod
	def doThis(self):
		pass
class StartState(State):
	def doThis(self):
		print('TV Switching ON...')
class StopState(State):
	def doThis(self):
		print('TV Switching OFF...')	
class TVContext(State):
	def __init__(self):
		self.state = None
	def getState(self):	
		return self.state
	def setState(self, state):
		self.state = state	
	def doThis(self):
		self.state.doThis()
if __name__ == '__main__':
	context = TVContext()
	start = StartState()
	stop = StopState()
	context.setState(stop)
	context.doThis()	

##三、现实世界中的例子
以一个计算机系统为例:它可以有多个状态,如开机、关机、挂起或休眠。
ComputerState接口:

  • state应定义两个属性,它们是name和allowed。属性name表示对象的状态,而属性allowed是定义允许进入的状态的对象的列表。
  • state必须定义一个switch()方法,由它来实际改变对象状态。
    实现了State接口的ConcreteState:
  • On:打开计算机。这时候允许的状态是Off、Suspend(挂起)和hibernate(休眠)。
  • Off:关闭计算机。这时候允许的状态只有On。
  • Hibernate:将计算机置于休眠模式。这时只能执行打开操作。
  • Suspend:使计算机挂起。一旦计算机挂起,就可以执行打开操作。

Context类(Computer)。上下文需要做两个主要的事情:

  • init*’:该方法定义了计算机的基本状态。
  • change():该方法将更改对象的状态,但是行为的实际更改是由ConcreteState类实现(On、Off、Suspend、Hibernate)的。
class ComputerState:
	name = 'state'
	allowed = []
	def switch(self, state):
		if state.name in self.allowed:
			print('Current::', self, ' => switched to new state', state.name)
			self.__class__ = state		##??__class__表示对类的引用
		else:
			print('Current::', self, ' => switched to', state.name, 'not possible.')
	def __str__(self):
		return self.name
		
class Off(ComputerState):
	name = 'off'
	allowed = ['on']	
class On(ComputerState):
	name = 'on'
	allowed = ['off', 'suspend', 'hibernate']
class Suspend(ComputerState):
	name = 'suspend'
	allowed = ['on']
class Hibernate(ComputerState):
	name = 'hibernate'
	allowed = ['on']
	
class Computer:
	def __init__(self, model = 'HP'):	##
		self.model = model
		self.state = Off()		##
	def change(self, state):
		self.state.switch(state)
		
if __name__ == '__main__':		
	comp = Computer()
	comp.change(On)
	comp.change(Off)
	
	comp.change(On)
	comp.change(Suspend)
	comp.change(Hibernate)
	
	comp.change(On)
	comp.change(Off)

'class’是每个类的内部属性。它是对类的引用。例如self.class.name’表示类的名称。在本例中,我们使用Python的’class’属性来改变状态。因此,当我们将状态传递给change()方法时,对象的类就可以在运行时动态更改。代码comp.change(On)将对象状态更改为On,然后就可以更改为不同的状态了,例如Suspend、Hibernate和Off。
##四、状态模式的优缺点
优点:

  • 在状态设计模式中,对象的行为是其状态的函数结果,并且行为在运行时根据状态而改变。这消除了对if/else或switch/case条件逻辑的依赖。
  • 使用状态模式,实现多态行为的好处是显而易见的,并且更易于添加状态来支持额外的行为。
  • 状态设计模式还提高了聚合性,因为特定于状态的行为被聚合到ConcreteState类中,并且放置在代码中的同一个地方。
  • 使用状态设计模式,通过只添加一个ConcreteState类来添加行为是非常容易的。因此,状态模式不仅改善了扩展应用程序行为时的灵活性,而且全面提高了代码的可维护性。

缺点:

  • 类爆炸:由于每个状态都需要在ConcreteState的帮助下定义,因此可能导致创建了太多功能较为单一的类。
  • 随着每个新行为的引入(即使添加行为只是添加一个ConcreteState),Context类都需要进行相应的更新以处理每个行为。这使得上下文行为更容易受到每个新的行为的影响。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值