状态模式适合哪些应用场景?
简化版
状态模式适合对象存在多个状态,并且不同状态下行为差异明显的场景。常见应用包括订单状态、工单流转、审批流程、播放器状态、连接会话、电梯控制、售后流程和游戏角色状态。
详细版
适合状态模式的场景通常具备这些特征:
- 对象有明确生命周期;
- 当前状态会影响行为;
- 状态判断逻辑很多;
- 状态之间有迁移关系;
- 新增状态或修改状态行为比较频繁。
典型场景包括:
- 订单:待支付、已支付、已发货、已完成、已取消;
- 工单:待处理、处理中、已解决、已关闭;
- 审批:草稿、待审批、已通过、已驳回;
- 播放器:播放、暂停、停止;
- TCP 连接:建立中、已连接、关闭中、已关闭;
- 电梯:运行、停止、开门、关门;
- 游戏角色:正常、眩晕、隐身、死亡。
不适合的场景是:状态很少、行为差异不大、状态变化不复杂,用普通条件判断更简单。
完整版教学
一、订单状态是最常见场景
订单状态非常典型,因为它有明确生命周期:
待支付 -> 已支付 -> 已发货 -> 已完成
不同状态下能执行的操作不同:
- 待支付可以支付、取消;
- 已支付可以发货、退款;
- 已发货可以确认收货;
- 已完成可以评价;
- 已取消不能再支付。
这类状态驱动行为非常适合状态模式。
二、工单和审批流程也适合
工单可能经历:
新建 -> 待分配 -> 处理中 -> 已解决 -> 已关闭
审批单可能经历:
草稿 -> 待审批 -> 已通过 / 已驳回
每个状态下允许的操作不同。比如已关闭工单不能继续处理,已通过审批不能再次编辑。
这些场景可以用状态模式封装每个状态下的操作规则。
三、播放器状态适合教学说明
播放器有:
播放中
暂停中
停止
同一个按钮在不同状态下行为不同。
比如点击播放:
- 停止状态:开始播放;
- 暂停状态:恢复播放;
- 播放状态:可能无操作或重新播放。
这个例子简单,很适合解释状态模式的思想。
四、连接和会话状态适合系统场景
网络连接、WebSocket 会话、登录会话也有状态。
比如连接状态:
未连接 -> 连接中 -> 已连接 -> 关闭中 -> 已关闭
不同状态下发送数据、关闭连接、重连的行为不同。
如果全靠条件判断,会产生很多边界 bug。状态模式能让每种连接状态自己处理操作。
五、游戏角色状态适合说明行为变化
游戏角色可能处于:
- 正常;
- 眩晕;
- 隐身;
- 加速;
- 死亡。
同一个操作,比如攻击、移动、释放技能,在不同状态下结果不同。
这种行为强依赖状态的场景,也适合状态模式。
六、什么时候不适合状态模式
如果只有两个状态,逻辑也很简单,比如启用和禁用:
if (enabled) {
...
}
直接判断可能更清楚。
如果状态很多但行为差异不大,只是状态值展示不同,也没必要拆很多状态类。
状态模式适合行为变化明显,不是只适合状态值多。
七、复杂流程要考虑状态机
如果状态迁移很多,还需要可视化、配置化、审计和守卫条件,状态模式可能不够。
比如金融交易状态、复杂审批流、跨系统订单履约,通常更适合状态机或流程引擎。
状态模式可以作为实现手段,但不要替代完整流程治理。
八、状态与行为耦合度决定适用性
播放器有 stopped、playing、paused 3 个状态,同一个 click 动作在三种状态下产生不同结果,适合封装为状态行为。
event + current state -> different behavior -> controlled transition
状态题的正确性落在“当前状态 + 事件 + 守卫条件 → 目标状态”这一条边上,而不是类数量上。每条边都要说明持久化原子性、重复事件结果和副作用触发时机,非法边则必须得到稳定且可观测的拒绝。
九、迁移一致性、幂等与并发验证
| 检查维度 | 应确认的内容 |
|---|---|
| 机制正确性 | 适用信号是同一操作在不同状态下有显著不同规则,而不是表里存在 status 字段。 |
| 适用边界 | 只有展示标签不同或一个简单布尔开关时无需状态类;跨多人长流程则可能需要状态机/工作流。 |
| 测试证据 | 覆盖正常迁移、重复事件、非法迁移、持久化失败和两个请求竞争同一版本 |
| 工程代价 | 重点评估状态数、迁移边数、一次迁移的数据库竞争,以及新增状态对完整迁移矩阵的影响 |
易错点:适用信号是同一操作在不同状态下有显著不同规则,而不是表里存在 status 字段。
十、常见误区与追问
- 误区:数据库表有 status 列就应该使用状态模式。 许多状态字段只用于标识和查询,只有行为分支复杂并持续增长时才值得对象化。
- 误区:把状态码换成状态类就自动消除了所有条件判断。 状态对象只能封装状态相关行为;持久化、并发控制、权限和跨聚合规则仍需显式设计。
- 追问:连接状态为什么适合举例? connect、send、close 在未连接、已连接、关闭状态下有不同合法性和实现。
- 追问:非法状态迁移应该静默忽略吗? 不应该;应返回明确业务错误并记录当前状态、事件和聚合标识,重复事件则按幂等规则单独处理。
- 追问:状态模式最容易漏掉哪类测试? 非法迁移、重复事件和并发竞争;它们比单线程成功路径更能证明状态模型可靠。
十一、加强记忆
状态模式适合“状态影响行为”的对象,比如订单、工单、审批、播放器、连接、电梯和游戏角色。判断标准不是状态数量多,而是不同状态下行为差异明显、条件判断复杂、状态迁移有规则。简单状态值判断不必强行套模式。