抽象类统一管理状态机生命周期,通过定义动作入口、迁移规则和上下文委托,确保语义一致性与可演进性。

用抽象类管理具有相同生命周期的状态机,本质是把“状态变化”这件事从散落的条件判断里拎出来,变成可复用、可验证、可演进的结构。关键不在于抽象类多复杂,而在于它是否真正承载了领域模型中状态流转的语义一致性。
统一生命周期契约,让状态行为有据可依
抽象类要定义整个生命周期中所有可能触发的动作入口,比如 init()、validate()、approve()、reject()、expire()、archive()。这些方法不写具体逻辑,只声明“每个状态都必须回应这个动作”。
- 所有具体状态类(如
DraftState、ReviewingState、ApprovedState)必须实现全部方法,哪怕只是抛异常或调用invalidOperation() - 方法签名建议带上下文对象(如
void approve(DomainContext context)),方便状态类内部驱动流转,比如context.setState(new ApprovedState()) - 抽象类可提供默认
onEnter()和onExit()模板方法,供子类选择性重写,用于统一埋点、日志或前置校验
状态迁移规则收口到抽象层,避免各模块各自为政
不同业务模块(如订单、合同、工单)若共享同一套生命周期阶段,它们的状态跳转逻辑应由抽象类统一约束。
- 在抽象类中内置合法迁移表,例如
Map<String, Set<String>> validTransitions = Map.of("DRAFT", Set.of("REVIEWING"), "REVIEWING", Set.of("APPROVED", "REJECTED")) - 提供
boolean canTransition(String from, String to)方法,子类调用super.canTransition(currentState, nextState)即可完成校验 - 若某模块需要扩展特殊跳转(如“已归档 → 重新激活”),可在抽象类中预留钩子(如
isSpecialTransitionAllowed()),而非绕过主规则
上下文与状态解耦,数据归属清晰
DomainContext 是唯一持有业务数据和当前状态引用的地方,它不参与判断,只做委托和托管。
- 状态字段声明为
private State currentState,提供setState(State newState),内部做合法性校验(如禁止从ARCHIVED直接切回DRAFT) - 所有状态变更必须通过
context.setState(...)触发,禁止在具体状态类中直接 new 上下文或修改外部变量 - 数据库持久化时,只存状态枚举值(如
"APPROVED"),加载时根据该值构造对应状态实例并注入 context
配合领域模型强化语义表达
抽象类不是孤立存在,它要嵌入领域建模过程:
- 状态名使用领域术语(如
PaymentPending而非State2),与领域专家对齐 - 每个具体状态类的职责是回答“在这个状态下,什么操作是合法的、会产生什么业务后果”,而不是“怎么查数据库”或“怎么发消息”
- 副作用(如发事件、更新缓存)由上下文或模板方法统一处理,状态类只专注规则——这保证了无论哪个模块接入,状态变更带来的可观测行为是一致的
不复杂但容易忽略

















