状态模式(State Pattern)

🧠 状态模式(State Pattern)

状态模式是一种行为型设计模式。它允许对象在其内部状态改变时改变其行为。一个对象的行为会随着它的状态改变而改变,状态模式可以帮助你处理对象在不同状态下的行为分支问题,使得对象的行为看起来像是"改变了类"。


🎯 为什么需要状态模式?

  1. 处理复杂的状态转移:当对象的行为受不同状态控制,并且状态之间的转移规则复杂时,使用状态模式可以清晰地处理不同的状态及其转移。
  2. 避免条件语句 :通过将状态转移的逻辑分散到各个状态类中,避免了在主类中大量的条件语句(如 if-elseswitch)。
  3. 扩展性:每个状态都封装成独立的类,新的状态可以轻松地添加到系统中,避免修改原有代码。

优缺点分析

优点 缺点
状态转换清晰,易于管理 增加了类的数量,系统变得更复杂
使得行为随状态变化,代码更加灵活 对于简单场景,状态模式可能显得过于复杂
易于扩展,增加新状态时只需新增类 状态类之间的关系可能难以理清

🧩 Python 示例:售卖机状态管理

我们通过一个售卖机的例子来展示状态模式。假设售卖机有三个状态:NoCoin(无硬币)、HasCoin(有硬币)、SoldOut(已售空),每个状态下,售卖机的行为不同。


1️⃣ 状态接口(State)

首先定义一个状态接口 ,所有具体状态类都要实现这个接口中的方法。这里用 Python 的 ABC 类来定义抽象类。

python 复制代码
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():发放商品的方法。

这些方法会被具体的状态类实现,来定义每个状态下如何响应这些操作。

2️⃣ 具体状态类(Concrete States)

接下来我们定义具体的状态类。每个状态类实现了 State 接口,并定义了不同的行为。

python 复制代码
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:表示售卖机售罄的状态。无法投币和转动曲柄。

3️⃣ 上下文类(VendingMachine)

然后,我们创建一个 上下文类(在状态模式中,通常是管理状态的核心类),这个类用于管理当前的状态以及切换状态。

python 复制代码
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() 等)都会调用当前状态的相应方法,从而实现不同状态下不同的行为。

4️⃣ 客户端代码:模拟使用售卖机

最后,我们编写客户端代码,模拟售卖机的操作过程。客户可以投币、转动曲柄以及退币。

python 复制代码
# 创建一个售卖机对象
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)

状态管理 使用状态 使用状态 使用状态 <<interface>> State +insert_coin() +eject_coin() +turn_crank() +dispense() NoCoinState +insert_coin() +eject_coin() +turn_crank() +dispense() HasCoinState +insert_coin() +eject_coin() +turn_crank() +dispense() SoldOutState +insert_coin() +eject_coin() +turn_crank() +dispense() VendingMachine +insert_coin() +eject_coin() +turn_crank() +dispense()


🧭 流程图(Mermaid)

User VendingMachine NoCoinState HasCoinState SoldOutState insert_coin() insert_coin() state change turn_crank() turn_crank() state change dispense() eject_coin() eject_coin() User VendingMachine NoCoinState HasCoinState SoldOutState


🧠 应用场景总结

场景 示例
状态机 游戏中角色的状态切换,如"待机","攻击","防御"
流程管理 任务处理的多个步骤,进度状态控制
GUI设计 按钮或控件的不同状态响应,例如"启用","禁用"
电梯系统 电梯的"上行","下行","空闲"等状态

总结口诀

状态模式

允许对象根据内部状态 改变其行为,避免大量的条件语句

✅ 每个状态封装成独立类,简化状态转移逻辑,使代码易于维护和扩展。


希望这次的例子更清晰了!如果有其他问题或需要进一步的解释,随时告诉我!

相关推荐
Code哈哈笑8 小时前
【图书管理系统】详细讲解用户登录:后端代码实现及讲解、前端代码讲解
前端·spring boot·后端·spring·状态模式
文件夹__iOS1 天前
状态模式 VS 策略模式
状态模式·策略模式
magic 2452 天前
深入理解 Spring MVC:DispatcherServlet 与视图解析机制
java·servlet·状态模式·springmvc
碎梦归途6 天前
23种设计模式-行为型模式之状态模式(Java版本)
java·jvm·设计模式·状态模式·软考·软件设计师·行为模式
茂桑7 天前
日常开发小Tips:后端返回带颜色的字段给前端
java·状态模式
free慢8 天前
设计模式(状态模式)
设计模式·状态模式
小陈098 天前
Java后端图形验证码的使用
java·开发语言·状态模式
CHQIUU11 天前
告别手动映射:在 Spring Boot 3 中优雅集成 MapStruct
spring boot·后端·状态模式
BXCQ_xuan12 天前
Django API 响应格式:一个新手踩坑记
python·django·状态模式