Python状态机实现疑问:中间State类作用及嵌套类与继承差异
状态机相关问题解答
为什么状态模式需要在具体状态和上下文之间设置抽象State类
你当前的实现场景极简单,所以暂时感知不到抽象State层的价值,它的核心作用有这几个:
- 定义统一的行为契约:强制所有具体状态必须实现约定的接口(比如你代码里的
button_press、transition),如果新增状态漏实现,静态检查阶段就会报错,避免运行时调用失败 - 抽离公共逻辑:所有状态通用的逻辑(比如非法输入报错、跳转前的权限校验)可以统一放在抽象State层实现,不用每个具体状态重复写冗余代码
- 统一类型标注:上下文(Lift类)可以明确声明
current_state的类型为抽象State,不管切换到哪个具体状态,类型都符合约束,大幅提升代码可读性和静态检查通过率
简化嵌套状态机相比传统状态机的能力损失
你的当前实现仅能满足极简单的固定场景,随着业务复杂度提升,会暴露这些问题:
- 可扩展性差:如果后续新增状态(比如电梯故障、满载、维保、临时楼层限制等),所有新状态的重复逻辑只能逐个复制粘贴,没有统一约束很容易写错,修改公共逻辑也要逐个改所有状态类
- 可测试性差:状态类嵌套在Lift内部,无法单独实例化做单元测试,必须依赖完整的Lift实例才能验证状态跳转逻辑
- 逻辑无法复用:状态类和Lift强绑定,如果你要做其他类型的电梯(比如货梯、消防梯),状态逻辑没法抽离复用,只能复制代码
- 耦合度过高:状态类直接依赖Lift的内部实现,如果你修改了Lift的方法名、属性名,所有状态类里的对应调用都要同步修改,维护成本极高
- 无法支持复杂多态行为:如果后续要新增状态通用行为(比如进入状态时的触发逻辑、离开状态时的清理逻辑),没有抽象层约束很容易出现部分状态漏实现的问题
嵌套类实现和继承Lift实现的核心区别
这两种实现是完全不同的语义,没有可比性:
- 你当前的嵌套类属于内部类,仅表达「这些状态类仅为Lift服务,不需要对外暴露」的语义,嵌套类本身不会继承Lift的任何属性和方法,所以你需要在初始化时传入Lift的实例,通过持有引用的方式访问Lift的功能
- 如果改成
class FloorOne(Lift)属于继承,语义上表达「FloorOne是Lift的一种子类」,完全不符合逻辑:楼层状态是电梯的一个属性,不是电梯的子类型。继承后FloorOne会自动持有Lift的所有属性,每个状态实例都会自带一套独立的current_state等属性,会直接导致状态管理混乱,属于典型的继承误用
对应示例代码
class Lift: def __init__(self): self.current_state = Lift.FloorOne(self) def show_input_error(self): print("Incorrect input") class FloorOne: def __init__(self, lift): self.lift = lift print("You are on Floor One") def button_press(self, num): self.transition(num) def transition(self, num): if num == 2: self.lift.current_state = Lift.FloorTwo(self.lift) elif num == 3: self.lift.current_state = Lift.FloorThree(self.lift) else: self.lift.show_input_error() class FloorTwo: def __init__(self, lift): self.lift = lift print("You are on Floor Two") def button_press(self, num): self.transition(num) def transition(self, num): if num == 1: self.lift.current_state = Lift.FloorOne(self.lift) elif num == 3: self.lift.current_state = Lift.FloorThree(self.lift) else: self.lift.show_input_error() class FloorThree: def __init__(self, lift): self.lift = lift print("You are on Floor Three") def button_press(self, num): self.transition(num) def transition(self, num): if num == 1: self.lift.current_state = Lift.FloorOne(self.lift) elif num == 2: self.lift.current_state = Lift.FloorTwo(self.lift) else: self.lift.show_input_error() lift = Lift() while True: goto = input("What floor would you like to go to?") lift.current_state.button_press(int(goto))
内容的提问来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

