如何在 Java 中利用 状态模式 消除类中复杂的 if-else 逻辑并实现状态行为封装
代码里一旦出现大量 if-else 或 switch-case 来判断对象状态、执行不同行为,维护成本就开始悄悄攀升了。更头疼的是,每次新增一个状态,都得去翻遍所有条件分支——改漏一个就是线上事故。有没有一种设计,能让状态变化本身决定该做什么,彻底跟那些冗长的条件判断说再见?状态模式就是干这个的。
代码里一旦出现大量 if-else 或 switch-case 来判断对象状态、执行不同行为,维护成本就开始悄悄攀升了。更头疼的是,每次新增一个状态,都得去翻遍所有条件分支——改漏一个就是线上事故。有没有一种设计,能让状态变化本身决定该做什么,彻底跟那些冗长的条件判断说再见?状态模式就是干这个的。

状态模式的核心思想
一句话概括:把对象在不同状态下的行为封装成独立的类,对象内部状态发生变化时,其行为也随之自动切换。不是用 if-else 去“看”当前状态再决定做什么,而是直接让“状态本身”来决定——对象只管把请求委托给当前状态实例,行为与条件判断彻底解耦。
典型 if-else 场景与问题
拿订单来举例再合适不过。一个订单对象通常有“待支付”“已支付”“已发货”“已完成”“已取消”等状态,每个操作(支付、发货、退款)都要先检查当前状态是否允许,再执行动作,最后更新状态。硬编码的结果就是:方法里塞满嵌套或并列的 if-else,看着就头疼。
这种写法的痛点很明显:
- 订单类膨胀到不行,既要管业务逻辑又要管状态流转,职责不单一
- 状态校验和行为逻辑混在一起,读代码就像在猜谜
- 加一个新状态(比如“部分发货”),所有涉及状态判断的方法都得改一遍
- 状态之间非法转移根本防不住——比如从“已完成”又跑去“支付”
用状态模式重构的关键步骤
以订单为例,落地只要四步,非常清爽:
- 定义状态接口:声明所有状态共有的行为方法,比如
pay()、ship()、cancel() - 为每种状态实现具体类:每个类只专注自己状态下的合法行为。例如
PaidState实现ship()(允许发货),但pay()直接抛异常或忽略 - 订单持有状态引用:用组合代替继承,订单持有一个
OrderState接口引用,初始设为CreatedState - 状态切换由状态自身控制:比如
CreatedState.pay()执行成功后,主动把订单的状态引用设为new PaidState(order)
这样一来,订单的 pay() 方法就简化为一行:currentState.pay(),零 if-else。
实际代码片段示意
先看状态接口:
interface OrderState {
void pay(Order order);
void ship(Order order);
void cancel(Order order);
}
具体状态之一——已支付状态:
class PaidState implements OrderState {
@Override
public void pay(Order order) {
throw new IllegalStateException("Already paid");
}
@Override
public void ship(Order order) {
System.out.println("Shipping...");
order.setState(new ShippedState(order)); // 自行切换状态
}
@Override
public void cancel(Order order) {
System.out.println("Cancelling paid order...");
order.setState(new CancelledState(order));
}
}
订单类(精简版):
class Order {
private OrderState state;
public Order() {
this.state = new CreatedState(this);
}
public void pay() { state.pay(this); }
public void ship() { state.ship(this); }
public void cancel() { state.cancel(this); }
public void setState(OrderState state) { this.state = state; }
}
需要留意的是:状态类可以持有对上下文(Order)的引用,用于读取数据或触发状态变更,但要避免循环依赖。


































