状态模式(State Pattern) 是一种行为型设计模式,允许对象在其内部状态发生改变时,改变其行为,就好像它改变了所属的类一样。
它将与状态相关的行为抽取为独立类,使状态切换更清晰、行为更灵活,避免了大量的条件分支。
✅ 场景痛点:条件分支混乱 & 行为难维护
面对多状态切换的场景,我们经常写出如下代码:
if (state == "草稿") { ... }
else if (state == "审核中") { ... }
else if (state == "已发布") { ... }
这类逻辑会导致:
状态逻辑紧耦合在一起,难以扩展
添加新状态风险极高,需遍历所有分支
单一方法中塞入过多职责
状态模式的目标:将每种状态的行为独立封装,替代条件语句,使状态变化过程更具弹性与可维护性。
✅ 类比说明:电梯的行为控制
电梯状态可能有:运行中、停止中、维护中。
不同状态下:
接到“上楼”指令时行为不同
接到“关门”请求时行为不同
使用状态模式可将“运行状态”和其行为分开,避免硬编码条件判断。
角色 |
说明 |
---|---|
Context |
环境类,持有当前状态对象,提供行为调用接口 |
State |
状态接口,定义所有状态共有的方法 |
ConcreteState |
具体状态类,实现各状态下的具体行为 |
✅ 1. State 接口(抽象状态)
public interface OrderState {
void handle(OrderContext context);
}
✅ 2. Context 类(订单上下文)
public class OrderContext {
private OrderState currentState;
public void setState(OrderState state) {
this.currentState = state;
}
public void process() {
currentState.handle(this);
}
}
✅ 3. 各具体状态类
草稿状态
public class DraftState implements OrderState {
public void handle(OrderContext context) {
System.out.println("当前状态:草稿,提交订单...");
context.setState(new SubmittedState());
}
}
已提交状态
public class SubmittedState implements OrderState {
public void handle(OrderContext context) {
System.out.println("当前状态:已提交,开始支付...");
context.setState(new PaidState());
}
}
已支付状态
public class PaidState implements OrderState {
public void handle(OrderContext context) {
System.out.println("当前状态:已支付,准备发货...");
context.setState(new ShippedState());
}
}
已发货状态
public class ShippedState implements OrderState {
public void handle(OrderContext context) {
System.out.println("当前状态:已发货,完成订单!");
}
}
✅ 4. 测试执行流程
public class Main {
public static void main(String[] args) {
OrderContext order = new OrderContext();
order.setState(new DraftState());
order.process(); // 提交订单
order.process(); // 支付
order.process(); // 发货
order.process(); // 完成
}
}
应用场景 |
描述 |
---|---|
状态随时间或事件切换的业务流 |
如订单流程、审批流程、任务状态流转等 |
有限状态集合,且状态行为差异明显 |
每个状态拥有独立逻辑,如游戏人物状态(攻击、防御、死亡) |
避免冗长的 if-else/switch 结构 |
结构灵活,便于维护和扩展 |
优点 |
描述 |
---|---|
消除了 if-else/switch 条件判断 |
每种状态独立维护逻辑 |
遵循开闭原则 |
添加新状态无需修改原有代码 |
状态切换清晰,行为封装独立 |
各状态逻辑清晰明确 |
有利于状态复用与测试 |
每个状态类可单独测试 |
缺点 |
场景示例 |
---|---|
状态类数量爆炸 |
状态过多时会导致类数量增加 |
状态切换控制分散 |
若状态切换太分散,难以管理状态流转 |
引入额外抽象成本 |
对于状态较少的场景,反而增加复杂度 |
❌ 缺点场景举例与解决方案
场景 1:复杂游戏角色状态爆炸
游戏中角色有十几种状态(移动、攻击、防御、中毒、隐身、眩晕、死亡…),每个状态之间又有交叉流转,导致状态类数量激增。
✅ 解决方案:
将状态分组聚合(如“生存状态组”、“技能状态组”)
使用状态工厂统一创建管理状态对象
场景 2:状态切换混乱导致逻辑错误
若状态切换逻辑被多个模块调用,且没有统一封装状态转移规则,可能造成状态错误(如订单直接从“草稿”跳到“已发货”)。
✅ 解决方案:
通过状态机控制器集中处理状态流转规则
引入“允许切换状态集”进行状态白名单控制
扩展方向 |
描述 |
---|---|
状态图可视化 |
使用状态图工具建模(如 PlantUML) |
状态持久化 |
当前状态可存储到数据库,支持恢复 |
状态与事件解耦 |
结合“事件驱动”模型进行状态变更 |
引入状态工厂模式 |
统一管理状态对象实例创建 |
状态模式 适用于对象需要频繁根据状态切换行为的业务场景。
适用前提:
状态有限且行为差异大
存在状态切换逻辑
使用建议:
控制状态类数量,防止“类爆炸”
管理状态转换流程,避免不合法状态跳转
与状态图建模工具结合使用,提升协作与可维护性
下一篇将带你深入讲解「策略模式」的核心思想与进阶用法