Python状态模式详解:原理、优缺点及糖果机实现

顾星河
顾星河
发布时间:2026-10-15| 5人浏览过
原创

本文深入解析Python中的状态模式,阐述其通过封装状态转换规则来应对对象行为随状态变化的场景。文章详细列举了该模式在提高代码可维护性和扩展性方面的优点,以及增加类数量和结构复杂性等缺点。结合经典的糖果机代码示例,展示了如何避免庞大的条件语句块,实现状态与行为的解耦,并探讨了其适用场景。

状态模式

状态模式是一种行为设计模式,它允许一个对象在其内部状态改变时,改变其行为表现。

该模式的主要优点包括:

  • 将状态转换的规则进行封装,使逻辑更加清晰。
  • 明确枚举所有可能的状态,在使用前需预先确定状态的种类。
  • 将与特定状态相关的行为封装到独立的类中,便于新增状态;只需改变对象的状态即可切换其行为。
  • 将状态转换逻辑与状态对象本身结合,避免了使用庞大且难以维护的条件语句块。
  • 支持多个环境对象共享同一个状态对象,从而减少系统中对象的总数。

然而,该模式也存在一些缺点:

  • 使用状态模式通常会增加系统中类和对象的数量。
  • 其结构设计和实现相对复杂,若使用不当可能导致程序结构和代码混乱。
  • 状态模式对“开闭原则”的支持并不完美。对于允许切换状态的场景,新增状态类往往需要修改负责状态转换的源代码,否则无法切换到新状态;同时,修改某个状态类的行为也需要调整对应的源代码。

状态模式适用于以下场景:

  • 对象的行为随着其内部状态的改变而改变的情况。
  • 作为复杂的条件判断或分支语句的替代方案。

代码示例

参考状态图,系统包含“有25分钱”、“没有25分钱”、“售出糖果”和“糖果售罄”这4种状态。同时对应4个动作:“投入25分钱”、“退回25分钱”、“转动曲柄”和“发放糖果”。

class State:
    # 定义state基类
    def insert_quarter(self):
        pass
    def eject_quarter(self):
        pass
    def turn_crank(self):
        pass
    def dispense(self):
        pass

class SoldOutState(State):
    # 继承State 类
    def __init__(self, gumball_machine):
        self.gumball_machine = gumball_machine
    def __str__(self):
        return "sold_out"
    def insert_quarter(self):
        print("You can't insert a quarter, the machine is sold out")
    def eject_quarter(self):
        print("You can't eject, you haven't inserted a quarter yet")
    def turn_crank(self):
        print("You turned, but ther are no gumballs")
    def dispense(self):
        print("No gumball dispensed")

class SoldState(State):
    # 继承State 类
    def __init__(self, gumball_machine):
        self.gumball_machine = gumball_machine
    def __str__(self):
        return "sold"
    def insert_quarter(self):
        print("Please wait, we're already giving you a gumball")
    def eject_quarter(self):
        print("Sorry, you already turned the crank")
    def turn_crank(self):
        print("Turning twice doesn't get you another gumball")
    def dispense(self):
        self.gumball_machine.release_ball()
        if gumball_machine.count > 0:
            self.gumball_machine.state = self.gumball_machine.no_quarter_state
        else:
            print("Oops, out of gumballs!")
            self.gumball_machine.state = self.gumball_machine.soldout_state

class NoQuarterState(State):
    # 继承State 类
    def __init__(self, gumball_machine):
        self.gumball_machine = gumball_machine
    def __str__(self):
        return "no_quarter"
    def insert_quarter(self):
        # 投币 并且改变状态
        print("You inserted a quarter")
        self.gumball_machine.state = self.gumball_machine.has_quarter_state
    def eject_quarter(self):
        print("You haven't insert a quarter")
    def turn_crank(self):
        print("You turned, but there's no quarter")
    def dispense(self):
        print("You need to pay first")

class HasQuarterState(State):
    # 继承State 类
    def __init__(self, gumball_machine):
        self.gumball_machine = gumball_machine
    def __str__(self):
        return "has_quarter"
    def insert_quarter(self):
        print("You can't insert another quarter")
    def eject_quarter(self):
        print("Quarter returned")
        self.gumball_machine.state = self.gumball_machine.no_quarter_state
    def turn_crank(self):
        print("You turned...")
        self.gumball_machine.state = self.gumball_machine.sold_state
    def dispense(self):
        print("No gumball dispensed")

class GumballMachine:
    def __init__(self, count=0):
        self.count = count
        # 找出所有状态,并创建实例变量来持有当前状态,然后定义状态的值
        self.soldout_state = SoldOutState(self)
        self.no_quarter_state = NoQuarterState(self)
        self.has_quarter_state = HasQuarterState(self)
        self.sold_state = SoldState(self)
        if count > 0:
            self.state = self.no_quarter_state
        else:
            self.state = self.soldout_state
    def __str__(self):
        return ">>> Gumball machine current state: %s" % self.state
    def insert_quarter(self):
        # 投入25分钱
        self.state.insert_quarter()
    def eject_quarter(self):
        # 退回25分
        self.state.eject_quarter()
        # print("state", self.state, type(self.state))
    def turn_crank(self):
        # 转动曲柄
        # print("state", self.state, type(self.state))
        self.state.turn_crank()
    def release_ball(self):
        # 发放糖果
        print("A gumball comes rolling out the slot...")
        if self.count > 0:
            self.count -= 1
        
if __name__ == "__main__":
    # 以下是代码测试
    gumball_machine = GumballMachine(5) # 装入5 个糖果
    print(gumball_machine)
    gumball_machine.insert_quarter() # 投入25分钱
    gumball_machine.turn_crank() # 转动曲柄
    print(gumball_machine)
    gumball_machine.insert_quarter() #投入25分钱
    gumball_machine.eject_quarter()  # 退钱
    gumball_machine.turn_crank()     # 转动曲柄
    print(gumball_machine)
    gumball_machine.insert_quarter() # 投入25分钱
    gumball_machine.turn_crank() # 转动曲柄 
    gumball_machine.insert_quarter() # 投入25分钱 
    gumball_machine.turn_crank()  # 转动曲柄
    gumball_machine.eject_quarter() # 退钱
    print(gumball_machine)

总结

本文到此结束,希望能为读者提供有价值的参考,欢迎继续关注本站获取更多技术内容。

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。