状态模式
状态模式用于把对象在不同状态下的行为封装到不同状态类中,让对象状态变化时行为也随之变化。
一句话理解:状态不同,行为不同,就把状态拆成类。
解决什么问题
订单有多个状态:
text
待支付 -> 已支付 -> 已发货 -> 已完成
待支付 -> 已取消如果所有状态判断都写在一个类里:
java
if ("WAIT_PAY".equals(status)) {
// pay
} else if ("PAID".equals(status)) {
// ship
} else if ("SHIPPED".equals(status)) {
// finish
}随着状态和动作增加,判断会越来越复杂。状态模式把不同状态下的行为拆出去。
基本结构
text
Context -> State
State -> handle(context)角色:
Context:上下文对象,持有当前状态。State:状态接口。ConcreteState:具体状态,定义该状态下的行为和状态流转。
Java 示例
状态接口:
java
interface OrderState {
void pay(OrderContext context);
void ship(OrderContext context);
String name();
}上下文:
java
class OrderContext {
private OrderState state;
OrderContext(OrderState state) {
this.state = state;
}
public void setState(OrderState state) {
this.state = state;
}
public void pay() {
state.pay(this);
}
public void ship() {
state.ship(this);
}
public String stateName() {
return state.name();
}
}待支付状态:
java
class WaitPayState implements OrderState {
public void pay(OrderContext context) {
System.out.println("pay success");
context.setState(new PaidState());
}
public void ship(OrderContext context) {
throw new IllegalStateException("order is not paid");
}
public String name() {
return "WAIT_PAY";
}
}已支付状态:
java
class PaidState implements OrderState {
public void pay(OrderContext context) {
throw new IllegalStateException("order already paid");
}
public void ship(OrderContext context) {
System.out.println("ship success");
context.setState(new ShippedState());
}
public String name() {
return "PAID";
}
}
class ShippedState implements OrderState {
public void pay(OrderContext context) {
throw new IllegalStateException("order already shipped");
}
public void ship(OrderContext context) {
throw new IllegalStateException("order already shipped");
}
public String name() {
return "SHIPPED";
}
}使用:
java
OrderContext order = new OrderContext(new WaitPayState());
order.pay();
order.ship();
System.out.println(order.stateName());使用场景
- 订单状态流转。
- 工单流程。
- 账号状态。
- TCP 连接状态。
- 工作流节点。
- 状态机。
优点
- 消除大量状态判断。
- 每个状态职责清晰。
- 状态流转逻辑更集中。
- 新增状态相对独立。
缺点
- 状态类数量增加。
- 状态流转分散在状态类中,整体流程需要额外文档或图辅助。
- 状态很多且规则复杂时,需要考虑状态机框架。
和策略模式的区别
| 模式 | 重点 |
|---|---|
| 状态 | 对象内部状态变化导致行为变化 |
| 策略 | 外部选择不同算法执行 |
状态模式通常会改变上下文状态;策略模式通常只是替换算法,不负责状态流转。
实战注意
订单、支付、审批这类严肃状态流转,最好配合状态枚举、数据库状态字段、状态流转表和幂等控制一起设计。