状态模式是一种行为型设计模式,其核心思想是:当一个对象的内部状态改变时,它的行为也会随之改变,就像对象的 “类” 发生了变化一样。该模式通过将对象不同状态对应的行为封装到独立的 “状态类” 中,让对象在不同状态下切换时,只需切换对应的状态对象,而非通过大量if-elseswitch判断状态。

状态模式的本质是 “将状态与行为绑定,并用状态对象管理状态切换” —— 对象本身不直接维护状态和实现状态对应的行为,而是委托给当前的 “状态对象”,从而简化状态管理逻辑,提高代码可维护性和扩展性。

image.png

状态模式的典型应用场景如下:

  1. 对象状态较多且状态切换频繁
    • 订单系统:待支付→已支付→已发货→已完成→已取消(多状态流转);
    • 电梯系统:停止→上升→下降→开门→关门(不同状态下行为不同,如 “上升中” 不可开门)。
  2. 对象行为随状态变化而变化
    • 播放器:播放中(可暂停 / 停止)→暂停中(可播放 / 停止)→停止中(可播放);
    • 网络连接:连接中(可发送数据 / 断开)→断开中(可重连)→重连中(可取消重连)。
  3. 避免大量条件判断
    • 传统代码:if (state == 待支付) { 执行支付逻辑 } else if (state == 已支付) { 执行发货逻辑 }
    • 状态模式:将每个 if 分支的逻辑封装到独立状态类,环境类直接委托给当前状态。

下面我将用 Java 代码实现状态模式,以订单状态流转为例,展示不同状态下订单行为的变化。

首先,我们根据业务场景将状态分为支付、运输和确认收货三个状态,然后把他们封装到一个状态类中

1
2
3
4
5
6
7
8
9
10
11
12
// 抽象状态类
public abstract class State {
// 支付行为
public abstract void pay(Order order);

// 发货行为
public abstract void ship(Order order);

// 确认收货行为
public abstract void confirmReceipt(Order order);
}

然后,我们定义具体的状态类,他们都继承这个State抽象类,但是只能执行自己的状态操作。定义如下:

  • PendingPaymentState(待支付状态):只能执行支付操作,支付后切换到已支付状态
  • PaidState(已支付状态):只能执行发货操作,发货后切换到已发货状态
  • ShippedState(已发货状态):只能执行确认收货操作,确认后切换到已完成状态
  • CompletedState(已完成状态):不能执行任何操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 具体状态类:待支付状态
public class PendingPaymentState extends State {
@Override
public void pay(Order order) {
System.out.println("订单 " + order.getOrderId() + " 支付成功");
// 支付后切换到已支付状态
order.setState(new PaidState());
}

@Override
public void ship(Order order) {
System.out.println("错误:订单 " + order.getOrderId() + " 尚未支付,不能发货");
}

@Override
public void confirmReceipt(Order order) {
System.out.println("错误:订单 " + order.getOrderId() + " 尚未支付,不能确认收货");
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 具体状态类:已支付状态
public class PaidState extends State {
@Override
public void pay(Order order) {
System.out.println("错误:订单 " + order.getOrderId() + " 已经支付,不能重复支付");
}

@Override
public void ship(Order order) {
System.out.println("订单 " + order.getOrderId() + " 已发货");
// 发货后切换到已发货状态
order.setState(new ShippedState());
}

@Override
public void confirmReceipt(Order order) {
System.out.println("错误:订单 " + order.getOrderId() + " 尚未发货,不能确认收货");
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 具体状态类:已发货状态
public class ShippedState extends State {
@Override
public void pay(Order order) {
System.out.println("错误:订单 " + order.getOrderId() + " 已经支付并发货,不能再次支付");
}

@Override
public void ship(Order order) {
System.out.println("错误:订单 " + order.getOrderId() + " 已经发货,不能重复发货");
}

@Override
public void confirmReceipt(Order order) {
System.out.println("订单 " + order.getOrderId() + " 已确认收货");
// 确认收货后切换到已完成状态
order.setState(new CompletedState());
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 具体状态类:已完成状态
public class CompletedState extends State {
@Override
public void pay(Order order) {
System.out.println("错误:订单 " + order.getOrderId() + " 已完成,无需支付");
}

@Override
public void ship(Order order) {
System.out.println("错误:订单 " + order.getOrderId() + " 已完成,无需发货");
}

@Override
public void confirmReceipt(Order order) {
System.out.println("错误:订单 " + order.getOrderId() + " 已完成,不能重复确认收货");
}
}

定义好这些状态后,我们的订单对象中就可以维护这个订单的当前状态、提供状态切换的方法,但具体的状态切换后执行的动作,延迟到具体的状态类中执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 环境类:订单类
public class Order {
private State currentState;
private final String orderId;

public Order(String orderId) {
this.orderId = orderId;
// 初始状态为待支付
this.currentState = new PendingPaymentState();
}

public void setState(State state) {
this.currentState = state;
}

public String getOrderId() {
return orderId;
}

// 支付行为,委托给当前状态
public void pay() {
currentState.pay(this);
}

// 发货行为,委托给当前状态
public void ship() {
currentState.ship(this);
}

// 确认收货行为,委托给当前状态
public void confirmReceipt() {
currentState.confirmReceipt(this);
}
}

最后,我们看客户端调用代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 客户端测试类
public class Client {
public static void main(String[] args) {
// 创建订单(初始状态为待支付)
Order order = new Order("ORD-123456");

// 执行一系列操作,观察状态变化
order.pay(); // 支付 -> 状态变为已支付
order.ship(); // 发货 -> 状态变为已发货
order.confirmReceipt(); // 确认收货 -> 状态变为已完成

// 尝试在已完成状态执行操作
order.pay(); // 应该提示错误
order.ship(); // 应该提示错误
}
}

上面的代码中:

  1. 订单创建时初始化状态为待支付状态
  2. 当调用订单的某个行为方法(如 pay ())时:
    • 订单将请求委托给当前状态对象
    • 状态对象执行该状态下的具体逻辑
    • 如果操作有效,状态对象会通过订单的 setState () 方法切换到新状态
  3. 状态切换后,订单的后续行为将由新的状态对象处理

这种设计模式的优势在于:

  • 避免了大量的 if-else 条件判断,代码结构更清晰
  • 每个状态的行为被封装在独立的类中,职责单一
  • 新增状态只需添加新的状态类,符合开闭原则
  • 状态切换逻辑集中在状态类中,便于维护和扩展