状态模式的本质是用多态替代条件分支,将状态决定行为的逻辑委托给具体状态类,通过替换State引用实现状态流转,并由守卫条件确保合法切换,上下文与状态双向协作各司其职。

状态模式的本质,就是把“状态决定行为”这件事从条件判断里抽出来,让多态成为状态流转的自然结果——不是靠 if 判定走哪条路,而是靠当前对象实际所属的状态类,自动调用对应方法。
用多态替代条件分支
传统写法中,订单对象要自己判断当前状态再执行逻辑,比如:if (status == PAID) { ship(); }。这种写法把行为和状态绑死在同一个类里,新增状态就得改这个类。而状态模式下,订单(Context)只持有一个 State 接口引用,所有操作都委托给当前状态对象。由于每个具体状态类(如 PaidState、ShippedState)都实现了同一接口,调用 context.handleShip() 时,JVM 或运行时会根据实际绑定的对象类型,自动分派到对应实现——这就是多态在起作用。
- 不需要在 Context 中写任何 if-else,行为差异完全由运行时类型决定
- 添加新状态只需新增一个 ConcreteState 实现类,不改动 Context 或其他状态类
- 编译期类型安全:State 接口定义了可响应的事件集,非法操作无法编译通过
状态流转即对象替换
状态变化不是修改某个字段值,而是替换成另一个状态对象。例如,当用户完成支付,UnpaidState 的 onPaymentSuccess() 方法会通知 Context 执行 setState(new PaidState())。此时 Context 内部的 State 引用指向了新实例,后续所有委托调用自动切换到 PaidState 的实现逻辑。
- 状态变更 = 引用重赋值,天然契合面向对象的“替换原则”
- 每个状态类只关注“我能做什么”和“我允许变成谁”,不关心其他状态怎么实现
- 状态对象本身无状态(不存业务数据),保证替换干净、无副作用
守卫条件驱动合法流转
多态确保了“行为正确”,但还需保证“流转合规”。状态模式要求每个 ConcreteState 实现 canEnterFrom(State from) 方法,由 Context 在 setState 前统一校验。比如 ShippedState.canEnterFrom() 只返回 true 当前状态是 PaidState,否则拒绝切换。
- 守卫逻辑集中定义,避免散落在各 handle 方法中导致绕过校验
- 非法状态跳转在进入新状态前就被拦截,不会产生中间脏状态
- 配合枚举定义的离散状态,形成编译期 + 运行期双重约束
上下文与状态双向协作
Context 不仅持有当前 State,还提供通用能力(如保存订单 ID、触发持久化、发布领域事件)。而 State 在需要时可回调 Context 的方法,比如 ShippedState 调用 context.deductInventory() 扣减库存,或 context.emit(ShippedEvent) 发布事件。
- State 专注“决策”(该不该变、变成谁),Context 负责“执行”(存库、发消息、调外部)
- 避免 State 类膨胀成业务逻辑容器,保持职责单一
- Context 成为状态机的“中枢神经”,统一管理事务边界与横切关注点

















