状态模式解决"对象行为随状态变化,导致大量 if/else"的问题——把每个状态封装成类,状态流转变成"切换状态对象"。订单状态机、电梯、游戏角色都是它的场景。这篇讲清它怎么消灭 if/else。
一、解决什么问题:状态多了 if/else 爆炸
订单有"待支付 → 已支付 → 已发货 → 已完成"的状态流转。不用状态模式,每个操作都要判断当前状态:
java
// 不用状态模式:if/else 判断状态,状态一多就爆炸
if (order.getStatus() == PENDING) {
// 待支付才能支付
} else if (order.getStatus() == PAID) {
// 已支付才能发货
} else if (...) { ... }状态一多,每个方法里都是 if/else 嵌套,改一处漏一处。状态模式:把每个状态封装成类,行为跟着状态走。
二、核心结构
java
// 状态接口:定义该状态下的行为
interface OrderState {
void pay(Order order);
void ship(Order order);
}
// 具体状态:待支付
class PendingState implements OrderState {
public void pay(Order order) {
System.out.println("支付成功");
order.setState(new PaidState()); // 状态流转:切到已支付
}
public void ship(Order order) { throw new IllegalStateException("待支付不能发货"); }
}
// 具体状态:已支付
class PaidState implements OrderState {
public void pay(Order order) { throw new IllegalStateException("已支付,不能重复支付"); }
public void ship(Order order) {
System.out.println("发货成功");
order.setState(new ShippedState());
}
}
// 订单:持有当前状态,行为委托给状态对象
class Order {
private OrderState state = new PendingState(); // 初始待支付
void setState(OrderState s) { this.state = s; }
void pay() { state.pay(this); } // 委托给当前状态
void ship() { state.ship(this); }
}
// 使用:订单自动按状态流转,没有 if/else
Order order = new Order();
order.pay(); // 待支付 → 支付成功 → 切到已支付
order.pay(); // 已支付 → 抛异常"不能重复支付"
order.ship(); // 已支付 → 发货成功关键:Order 把行为委托给"当前状态对象",状态切换 = 换一个状态对象。每个状态自己决定"这个状态下能做什么、做了之后切到哪个状态",逻辑内聚在状态类里。
三、核心价值
- 消灭 if/else:状态判断分散到各状态类里,不用集中写 if/else
- 状态独立:加新状态 = 加一个状态类,不改已有代码
- 行为内聚:每个状态的"能做什么 + 流转到哪"集中在一处
四、实际应用
- 订单状态机:待支付/已支付/已发货/已完成
- 游戏角色:站立/奔跑/跳跃(每个状态的行为不同)
- 电梯:运行/停止/开门/关门
小结
- 状态模式把"状态"封装成类,行为随状态切换
- 状态流转 = 换状态对象,消灭 if/else
- 典型:订单状态机、游戏角色、电梯
相关:《策略模式》(状态是"对象内部状态变化换行为",策略是"外部传入策略换算法",结构像但语义不同)。
