多态结合状态模式的核心是让状态对象自主决定行为与流转。通过State接口统一动作入口(如pressStart),各状态类独立实现自身逻辑,上下文仅委托调用;状态转移由当前状态内部驱动,新增状态或操作无需修改原有代码,符合开闭原则。

多态结合状态模式管理行为转换,核心是把“状态决定行为”这件事交给对象自己,而不是靠一堆 if 判断去猜它现在是什么状态、该干什么。
用接口统一行为入口,不暴露状态标识
定义 State 接口时,方法名要体现动作意图,比如 pressStart()、pressPause()、onTimeout(),而不是 getStateName() 或 isRunning()。这样调用方不用先判断状态再分支调用——直接发指令,由当前状态类决定接不接、怎么响应。
- 不写
if (state == RUNNING) player.start();,而是player.pressStart(); - 每个具体状态类只实现它能处理的动作;对不支持的操作,可抛 UnsupportedOperationException 或静默忽略
- 避免在外部用字符串或枚举做条件跳转,否则多态就失效了
状态流转由状态自己驱动,上下文只负责委托
上下文类(如 Player、Order、Elevator)不包含任何状态判断逻辑,也不控制“下一步该变什么”。它只持有一个 State 类型的引用,并在事件触发时调用 currentState.handle(event) ——真正决定是否切换、切到哪里的,是当前状态对象内部的逻辑。
- RunningState 的 pressPause() 方法里,执行完暂停动作后主动调用
context.changeState(new PausedState()) - PausedState 收到 pressResume(),就调用
context.changeState(new RunningState()) - 状态间转移规则被封装在各自类中,新增状态不影响已有类
每个状态独立成类,行为与职责彻底解耦
IdleState、RunningState、PausedState 等不是简单标记,而是承载完整行为逻辑的实体。它们共享同一接口,但内部实现完全隔离:数据访问方式、副作用处理、边界校验都各自封闭。
- 例如订单的 cancel() 在待支付状态走退款流程,在已发货状态则返回拒绝提示
- 所有状态类都不依赖彼此,也不依赖上下文的具体实现,只通过接口与上下文通信
- 测试时可单独实例化任一状态类,传入 mock 上下文验证其行为
新增状态和操作都不动老代码,符合开闭原则
加一种新状态?只需新增一个 ConcreteState 实现类,实现对应方法,再让某个现有状态在合适时机把它设为下一个状态即可。加一个新操作?在 State 接口中增加方法,所有具体状态类选择性实现——编译器会提醒你补全,不会漏掉。
- 不需要修改 Context 类里的任何 if-else 分支
- 不需要改动其他状态类的代码
- 状态类之间无继承关系,互不影响,复用也更安全
不复杂但容易忽略:关键不在用了接口和继承,而在谁掌握状态流转的决策权。只要转移逻辑从外部条件语句移到状态对象内部,多态才算真正落地。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











