Python 状态模式

Python 中的状态模式(State Pattern)

状态模式是一种行为型设计模式,其核心目的是:
允许一个对象在其内部状态改变时改变它的行为。从外部看,就像对象改变了其类一样。

形象比喻:就像人的心情——开心时会笑、生气时会生气、疲惫时会休息。同一人(上下文对象),因为内部状态不同,行为完全不同。

状态模式的优点

  • 消除庞大的条件判断语句(if-elif-else)
  • 将每个状态的行为局部化到各自的类中,符合单一职责原则
  • 状态转换显式化:更容易理解和管理状态迁移规则
  • 易于扩展新状态:新增状态只需新增类,不修改原有代码
  • 对象行为随状态动态变化,非常灵活

典型应用场景

  • 订单状态机(待支付 → 已支付 → 发货中 → 已完成 → 退款)
  • TCP 连接状态(LISTEN → SYN_SENT → ESTABLISHED → CLOSED)
  • 游戏角色状态(正常、攻击、中毒、眩晕、无敌)
  • 工作流引擎(审批流程)
  • UI 控件状态(启用、禁用、悬停、焦点)

Python 实现示例:订单状态机

from abc import ABC, abstractmethod

# 上下文(Context):持有当前状态
class Order:
    def __init__(self):
        self.state = PendingPaymentState(self)  # 初始状态:待支付
        self.order_id = "ORD12345"

    def set_state(self, state):
        self.state = state
        print(f"订单 {self.order_id} 状态变更为: {state.__class__.__name__}")

    def pay(self):
        self.state.pay()

    def ship(self):
        self.state.ship()

    def complete(self):
        self.state.complete()

    def refund(self):
        self.state.refund()

    def __str__(self):
        return f"订单 {self.order_id} [{self.state.__class__.__name__}]"

# 抽象状态(State)
class OrderState(ABC):
    def __init__(self, order: Order):
        self.order = order

    @abstractmethod
    def pay(self):
        pass

    @abstractmethod
    def ship(self):
        pass

    @abstractmethod
    def complete(self):
        pass

    @abstractmethod
    def refund(self):
        pass

# 具体状态1:待支付
class PendingPaymentState(OrderState):
    def pay(self):
        print("支付成功!")
        self.order.set_state(PaidState(self.order))

    def ship(self):
        print("错误:订单尚未支付,无法发货")

    def complete(self):
        print("错误:订单尚未支付,无法完成")

    def refund(self):
        print("错误:订单尚未支付,无法退款")

# 具体状态2:已支付
class PaidState(OrderState):
    def pay(self):
        print("错误:订单已支付,无需重复支付")

    def ship(self):
        print("开始发货...")
        self.order.set_state(ShippedState(self.order))

    def complete(self):
        print("错误:订单尚未发货,无法完成")

    def refund(self):
        print("退款处理中...")
        self.order.set_state(RefundingState(self.order))

# 具体状态3:已发货
class ShippedState(OrderState):
    def pay(self):
        print("错误:订单已支付")

    def ship(self):
        print("错误:订单已发货,无需重复发货")

    def complete(self):
        print("订单已签收,交易完成!")
        self.order.set_state(CompletedState(self.order))

    def refund(self):
        print("发货后退款需审核...")
        # 可以转到另一个状态,或保持当前

# 具体状态4:已完成
class CompletedState(OrderState):
    def pay(self): print("订单已完成")
    def ship(self): print("订单已完成")
    def complete(self): print("订单已完成")
    def refund(self): print("已完成订单不支持退款")

# 具体状态5:退款中
class RefundingState(OrderState):
    def pay(self): print("退款中...")
    def ship(self): print("退款中...")
    def complete(self): print("退款中...")
    def refund(self): print("退款处理完成")
    # 可以转到 RefundedState 等

# 客户端使用
if __name__ == "__main__":
    order = Order()
    print(order)

    order.pay()        # → PaidState
    print(order)

    order.ship()       # → ShippedState
    print(order)

    order.complete()   # → CompletedState
    print(order)

    print("\n--- 尝试非法操作 ---")
    order.pay()        # 已支付,再支付报错
    order.refund()     # 已完成,不支持退款

输出

订单 ORD12345 [PendingPaymentState]
支付成功!
订单 ORD12345 状态变更为: PaidState
订单 ORD12345 [PaidState]
开始发货...
订单 ORD12345 状态变更为: ShippedState
订单 ORD12345 [ShippedState]
订单已签收,交易完成!
订单 ORD12345 状态变更为: CompletedState
订单 ORD12345 [CompletedState]

--- 尝试非法操作 ---
错误:订单已支付,无需重复支付
已完成订单不支持退款

Pythonic 简化版:使用字典 + 函数(适合简单状态机)

当状态不多、行为简单时,可以避免创建多个类:

class SimpleOrder:
    def __init__(self):
        self.state = "pending"
        self.states = {
            "pending": {
                "pay": lambda: self.transition("paid"),
                "ship": lambda: print("不能发货"),
            },
            "paid": {
                "pay": lambda: print("已支付"),
                "ship": lambda: self.transition("shipped"),
                "refund": lambda: self.transition("refunding"),
            },
            "shipped": {
                "complete": lambda: self.transition("completed"),
            },
            "completed": {
                "pay": lambda: print("已完成"),
                "refund": lambda: print("不支持退款"),
            },
        }

    def transition(self, new_state):
        print(f"状态变更为: {new_state}")
        self.state = new_state

    def action(self, cmd):
        handler = self.states.get(self.state, {}).get(cmd)
        if handler:
            handler()
        else:
            print(f"当前状态 {self.state} 不支持操作 {cmd}")

# 使用
order = SimpleOrder()
order.action("pay")
order.action("ship")
order.action("complete")

状态模式结构总结

角色说明
Context上下文(Order),持有当前状态引用
State抽象状态接口(OrderState)
ConcreteState具体状态类(PendingPaymentState 等)

状态模式 vs 策略模式对比

模式目的切换时机典型场景
状态行为随内部状态改变运行时自动切换订单、TCP、游戏角色
策略行为算法可外部替换外部手动设置支付方式、排序算法

关键区别:状态模式中,状态对象自己决定下一个状态(内部驱动);策略模式中,客户端决定使用哪个策略(外部驱动)。

Python 中的实用建议

  • 复杂状态机:使用类实现状态模式(清晰、可维护)
  • 简单状态:用枚举 + 字典映射行为
  • 结合枚举更安全
from enum import Enum

class OrderStatus(Enum):
    PENDING = "pending"
    PAID = "paid"
    SHIPPED = "shipped"
    COMPLETED = "completed"

class Order:
    def __init__(self):
        self.status = OrderStatus.PENDING
  • 真实项目中常见:
  • Django 的模型状态字段 + 状态迁移
  • Celery 任务状态
  • 游戏引擎中的角色状态系统

注意事项

  • 状态类不要太多(否则维护困难)
  • 确保所有状态都实现了完整接口(避免遗漏操作)
  • 状态转换逻辑要集中管理(避免分散在多个地方)

状态模式是构建复杂状态机的最佳实践之一,能让状态逻辑清晰、可扩展、可测试。

如果你想看更高级的例子(如游戏角色多状态叠加、带超时自动转状态、工作流引擎实现),或者如何与备忘录模式结合实现状态快照,欢迎继续问!

文章已创建 3511

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部