状态模式是一种行为型设计模式。它允许对象在其内部状态改变时改变其行为。一个对象的行为会随着它的状态改变而改变,状态模式可以帮助你处理对象在不同状态下的行为分支问题,使得对象的行为看起来像是“改变了类”。
if-else
或 switch
)。✅ 优点 | ❌ 缺点 |
---|---|
状态转换清晰,易于管理 | 增加了类的数量,系统变得更复杂 |
使得行为随状态变化,代码更加灵活 | 对于简单场景,状态模式可能显得过于复杂 |
易于扩展,增加新状态时只需新增类 | 状态类之间的关系可能难以理清 |
我们通过一个售卖机的例子来展示状态模式。假设售卖机有三个状态:NoCoin
(无硬币)、HasCoin
(有硬币)、SoldOut
(已售空),每个状态下,售卖机的行为不同。
首先定义一个状态接口,所有具体状态类都要实现这个接口中的方法。这里用 Python 的 ABC
类来定义抽象类。
from abc import ABC, abstractmethod
class State(ABC):
@abstractmethod
def insert_coin(self):
pass
@abstractmethod
def eject_coin(self):
pass
@abstractmethod
def turn_crank(self):
pass
@abstractmethod
def dispense(self):
pass
State
类是一个抽象基类,包含了四个方法:
insert_coin()
:投币方法。eject_coin()
:退币方法。turn_crank()
:转动曲柄的方法。dispense()
:发放商品的方法。这些方法会被具体的状态类实现,来定义每个状态下如何响应这些操作。
接下来我们定义具体的状态类。每个状态类实现了 State
接口,并定义了不同的行为。
class NoCoinState(State):
def __init__(self, machine):
self.machine = machine
def insert_coin(self):
'''难点:状态转移
-self.machine:指的是当前的 VendingMachine 对象(售卖机)。
-self.machine.no_coin_state:这是 VendingMachine 类中的一个属性,表示售卖机当前处于 NoCoinState 状态(即没有投入硬币的状态)。no_coin_state 是 VendingMachine 类的一个状态实例,属于 NoCoinState 类型。
-self.machine.set_state(self.machine.no_coin_state):这行代码的作用是通过set_state() 方法,将售卖机的当前状态设置为 NoCoinState。即将售卖机的状态转为 "没有硬币"。
'''
print("Coin inserted")
self.machine.set_state(self.machine.has_coin_state)
def eject_coin(self):
print("No coin to eject")
def turn_crank(self):
print("Insert coin first!")
def dispense(self):
print("Insert coin first!")
class HasCoinState(State):
def __init__(self, machine):
self.machine = machine
def insert_coin(self):
print("Coin already inserted")
def eject_coin(self):
print("Coin ejected")
self.machine.set_state(self.machine.no_coin_state)
def turn_crank(self):
print("Turn crank")
self.machine.set_state(self.machine.sold_out_state)
self.machine.dispense()
def dispense(self):
print("No item dispensed")
class SoldOutState(State):
def __init__(self, machine):
self.machine = machine
def insert_coin(self):
print("Machine is sold out")
def eject_coin(self):
print("No coin to eject")
def turn_crank(self):
print("No item to dispense")
def dispense(self):
print("Machine is sold out")
NoCoinState
:表示没有硬币的状态。投币后状态转到 HasCoinState
。HasCoinState
:表示已经投币的状态。转动曲柄时,状态转到 SoldOutState
并发放商品。SoldOutState
:表示售卖机售罄的状态。无法投币和转动曲柄。然后,我们创建一个 上下文类(在状态模式中,通常是管理状态的核心类),这个类用于管理当前的状态以及切换状态。
class VendingMachine:
def __init__(self):
self.no_coin_state = NoCoinState(self)
self.has_coin_state = HasCoinState(self)
self.sold_out_state = SoldOutState(self)
self.state = self.no_coin_state # 初始状态是没有投币
def set_state(self, state: State):
self.state = state
def insert_coin(self):
self.state.insert_coin()
def eject_coin(self):
self.state.eject_coin()
def turn_crank(self):
self.state.turn_crank()
def dispense(self):
self.state.dispense()
VendingMachine
类管理了所有的状态,并通过 set_state()
方法来切换当前的状态。insert_coin()
、eject_coin()
等)都会调用当前状态的相应方法,从而实现不同状态下不同的行为。最后,我们编写客户端代码,模拟售卖机的操作过程。客户可以投币、转动曲柄以及退币。
# 创建一个售卖机对象
vending_machine = VendingMachine()
# 测试状态切换
vending_machine.insert_coin() # 投币
vending_machine.turn_crank() # 转动曲柄,发放商品
vending_machine.eject_coin() # 退币
# 再次测试
vending_machine.insert_coin() # 投币
vending_machine.turn_crank() # 转动曲柄,发放商品
Coin inserted
Turn crank
No item dispensed
Coin ejected
Coin inserted
Turn crank
No item dispensed
insert_coin()
被调用时,状态从 NoCoinState
转变为 HasCoinState
。turn_crank()
被调用时,状态从 HasCoinState
转变为 SoldOutState
,并执行发放商品的操作。场景 | 示例 |
---|---|
状态机 | 游戏中角色的状态切换,如“待机”,“攻击”,“防御” |
流程管理 | 任务处理的多个步骤,进度状态控制 |
GUI设计 | 按钮或控件的不同状态响应,例如“启用”,“禁用” |
电梯系统 | 电梯的“上行”,“下行”,“空闲”等状态 |
状态模式:
✅ 允许对象根据内部状态改变其行为,避免大量的条件语句。
✅ 每个状态封装成独立类,简化状态转移逻辑,使代码易于维护和扩展。
希望这次的例子更清晰了!如果有其他问题或需要进一步的解释,随时告诉我!