状态模式(State Pattern)
🧠 状态模式(State Pattern)
状态模式是一种行为型设计模式。它允许对象在其内部状态改变时改变其行为。一个对象的行为会随着它的状态改变而改变,状态模式可以帮助你处理对象在不同状态下的行为分支问题,使得对象的行为看起来像是“改变了类”。
🎯 为什么需要状态模式?
- 处理复杂的状态转移:当对象的行为受不同状态控制,并且状态之间的转移规则复杂时,使用状态模式可以清晰地处理不同的状态及其转移。
- 避免条件语句:通过将状态转移的逻辑分散到各个状态类中,避免了在主类中大量的条件语句(如
if-else
或switch
)。 - 扩展性:每个状态都封装成独立的类,新的状态可以轻松地添加到系统中,避免修改原有代码。
✅ 优缺点分析
✅ 优点 | ❌ 缺点 |
---|---|
状态转换清晰,易于管理 | 增加了类的数量,系统变得更复杂 |
使得行为随状态变化,代码更加灵活 | 对于简单场景,状态模式可能显得过于复杂 |
易于扩展,增加新状态时只需新增类 | 状态类之间的关系可能难以理清 |
🧩 Python 示例:售卖机状态管理
我们通过一个售卖机的例子来展示状态模式。假设售卖机有三个状态:NoCoin
(无硬币)、HasCoin
(有硬币)、SoldOut
(已售空),每个状态下,售卖机的行为不同。
1️⃣ 状态接口(State)
首先定义一个状态接口,所有具体状态类都要实现这个接口中的方法。这里用 Python 的 ABC
类来定义抽象类。
from abc import ABC, abstractmethodclass State(ABC):@abstractmethoddef insert_coin(self):pass@abstractmethoddef eject_coin(self):pass@abstractmethoddef turn_crank(self):pass@abstractmethoddef dispense(self):pass
-
State
类是一个抽象基类,包含了四个方法:insert_coin()
:投币方法。eject_coin()
:退币方法。turn_crank()
:转动曲柄的方法。dispense()
:发放商品的方法。
这些方法会被具体的状态类实现,来定义每个状态下如何响应这些操作。
2️⃣ 具体状态类(Concrete States)
接下来我们定义具体的状态类。每个状态类实现了 State
接口,并定义了不同的行为。
class NoCoinState(State):def __init__(self, machine):self.machine = machinedef 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 = machinedef 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 = machinedef 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
:表示售卖机售罄的状态。无法投币和转动曲柄。
3️⃣ 上下文类(VendingMachine)
然后,我们创建一个 上下文类(在状态模式中,通常是管理状态的核心类),这个类用于管理当前的状态以及切换状态。
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 = statedef 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()
等)都会调用当前状态的相应方法,从而实现不同状态下不同的行为。
4️⃣ 客户端代码:模拟使用售卖机
最后,我们编写客户端代码,模拟售卖机的操作过程。客户可以投币、转动曲柄以及退币。
# 创建一个售卖机对象
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
,并执行发放商品的操作。
🧭 类图(Mermaid)
🧭 流程图(Mermaid)
🧠 应用场景总结
场景 | 示例 |
---|---|
状态机 | 游戏中角色的状态切换,如“待机”,“攻击”,“防御” |
流程管理 | 任务处理的多个步骤,进度状态控制 |
GUI设计 | 按钮或控件的不同状态响应,例如“启用”,“禁用” |
电梯系统 | 电梯的“上行”,“下行”,“空闲”等状态 |
✅ 总结口诀
状态模式:
✅ 允许对象根据内部状态改变其行为,避免大量的条件语句。
✅ 每个状态封装成独立类,简化状态转移逻辑,使代码易于维护和扩展。
希望这次的例子更清晰了!如果有其他问题或需要进一步的解释,随时告诉我!