状态模式的优缺点是什么?
简化版
状态模式的优点是消除复杂状态判断、把状态行为封装清楚、让状态迁移更符合开闭原则。缺点是会增加类数量,状态关系分散后可能不易看全貌;如果状态很多、迁移复杂,单纯状态模式可能不如显式状态机清晰。
详细版
状态模式的优点:
- 减少大量 if else 或 switch;
- 每个状态类职责清晰;
- 状态行为和迁移规则更容易局部维护;
- 新增状态时对原有代码影响较小;
- 客户端不用关心对象内部状态。
状态模式的缺点:
- 状态类数量增加;
- 状态迁移关系可能分散在各状态类中;
- 状态很多时维护成本上升;
- 复杂业务仍要处理持久化、并发、事务和幂等;
- 如果只是简单状态判断,使用状态模式可能过度设计。
面试中要补充:状态模式适合状态驱动行为明显的对象,不适合状态少、逻辑简单、变化不大的场景。
完整版教学
一、优点一:减少条件分支
状态模式最直观的价值是消除复杂条件判断。
没有状态模式时:
if (status == WAIT_PAY) {
...
} else if (status == PAID) {
...
} else if (status == SHIPPED) {
...
}
有状态模式后,行为交给当前状态对象:
state.cancel(context);
多态替代了条件判断。
二、优点二:状态职责更清晰
每个状态类只关心自己状态下的行为。
比如:
WaitPayState只关心待支付能做什么;PaidState只关心已支付能做什么;ShippedState只关心已发货能做什么。
这种组织方式比一个大类判断所有状态更容易理解。
三、优点三:扩展状态更自然
如果新增一个“售后中”状态,使用状态模式时可以新增 AfterSaleState。
相比在很多方法里增加:
else if (status == AFTER_SALE)
状态模式更符合开闭原则。
当然,如果新增状态会影响很多已有状态的迁移关系,仍然需要修改相关状态类或迁移表。
四、缺点一:类数量增加
状态模式会为每个状态创建一个类。
状态少时很清爽,状态多时类数量明显增加。
比如订单状态有几十种,如果每个状态再实现十几个操作,代码规模会很大。
所以状态模式适合状态行为差异明显的场景,不适合为了两三个简单判断强行拆类。
五、缺点二:状态迁移关系可能分散
如果每个状态类都自己决定下一个状态,完整状态图会分散在多个类中。
比如:
WaitPayState 里有一部分迁移
PaidState 里有一部分迁移
ShippedState 里有一部分迁移
要看全局状态流转,需要打开很多文件。
复杂业务中可以用状态迁移表、状态机框架或文档把全局关系显式化。
六、缺点三:工程问题不会自动消失
状态模式只是代码结构模式,不自动解决:
- 数据库状态一致性;
- 并发状态更新;
- 支付回调幂等;
- 消息可靠投递;
- 事务回滚;
- 状态变更审计。
真实系统里,状态模式需要和事务、锁、日志、状态机等机制配合。
七、什么时候优点会变成负担
如果状态数量很少,操作也很简单:
if (enabled) {
doSomething();
}
这种场景没必要上状态模式。
模式引入的类和抽象会超过它节省的复杂度。
八、分支收敛与类、迁移成本的交换
6 个状态、4 个动作的集中判断最多形成 24 个组合;拆状态类后每类只关心本状态动作,但系统会新增约 6 个类。
central 6x4 branches -> 6 state modules + explicit transition graph
状态题的正确性落在“当前状态 + 事件 + 守卫条件 → 目标状态”这一条边上,而不是类数量上。每条边都要说明持久化原子性、重复事件结果和副作用触发时机,非法边则必须得到稳定且可观测的拒绝。
九、迁移一致性、幂等与并发验证
| 检查维度 | 应确认的内容 |
|---|---|
| 机制正确性 | 状态模式把复杂度从条件矩阵迁到状态对象与迁移图,复杂度被组织而非消失。 |
| 适用边界 | 状态行为频繁变化时内聚收益大;状态很少且无行为差异时,新增类型和跳转会降低可读性。 |
| 测试证据 | 覆盖正常迁移、重复事件、非法迁移、持久化失败和两个请求竞争同一版本 |
| 工程代价 | 重点评估状态数、迁移边数、一次迁移的数据库竞争,以及新增状态对完整迁移矩阵的影响 |
易错点:状态模式把复杂度从条件矩阵迁到状态对象与迁移图,复杂度被组织而非消失。
十、常见误区与追问
- 误区:状态类越多,扩展新状态就越容易。 新状态还可能要求检查所有事件、迁移和持久化映射,完整性成本依然存在。
- 误区:把状态码换成状态类就自动消除了所有条件判断。 状态对象只能封装状态相关行为;持久化、并发控制、权限和跨聚合规则仍需显式设计。
- 追问:如何防止迁移关系分散? 维护一张权威状态图或迁移表,并用参数化测试覆盖所有合法和非法边。
- 追问:非法状态迁移应该静默忽略吗? 不应该;应返回明确业务错误并记录当前状态、事件和聚合标识,重复事件则按幂等规则单独处理。
- 追问:状态模式最容易漏掉哪类测试? 非法迁移、重复事件和并发竞争;它们比单线程成功路径更能证明状态模型可靠。
十一、加强记忆
状态模式的优点是少 if else、职责清晰、扩展状态方便;缺点是类变多、状态图分散、复杂迁移仍需治理。答题时要强调:它解决代码组织问题,不自动解决状态持久化、并发、事务和幂等等工程问题。