一、引言
在软件开发中,我们经常遇到这样的场景:同一个对象在不同状态下表现出不同的行为。传统的做法是使用大量的 if-else 或 switch-case 语句,但随着状态增多,代码会变得越来越难以维护。状态模式正是为解决这一问题而生。
本文将深入介绍状态模式的概念、实现方式,以及在Spring框架中的实际应用,帮助你掌握这一重要的设计模式。
二、什么是状态模式?
2.1 定义
状态模式(State Pattern)允许对象在内部状态改变时改变它的行为,对象看起来似乎修改了它的类。这是一种行为型设计模式。
2.2 核心思想
- 将状态相关的行为封装到独立的状态类中
- 通过委派将行为委托给当前状态对象处理
- 状态转换可以由Context或State类管理
2.3 模式结构
┌─────────────────┐ ┌─────────────────┐
│ Context │ │ State │
├─────────────────┤ ├─────────────────┤
│ - state: State │─────▶│ + handle() │
├─────────────────┤ └─────────────────┘
│ + request() │ ▲
│ + setState() │ │
└─────────────────┘ ┌────────┴────────┐
│ │
┌─────────┴──────┐ ┌───────┴─────────┐
│ ConcreteStateA│ │ ConcreteStateB │
├────────────────┤ ├─────────────────┤
│ + handle() │ │ + handle() │
└────────────────┘ └─────────────────┘
三、Java实战:订单状态管理系统
让我们通过一个完整的订单状态管理示例,深入理解状态模式的应用。
3.1 状态接口定义
java
/**
* 订单状态接口
* 定义订单在不同状态下支持的操作
*/
public interface OrderState {
/**
* 支付操作
* @param order 订单上下文
*/
void pay(OrderContext order);
/**
* 发货操作
* @param order 订单上下文
*/
void ship(OrderContext order);
/**
* 确认收货操作
* @param order 订单上下文
*/
void confirm(OrderContext order);
/**
* 取消订单操作
* @param order 订单上下文
*/
void cancel(OrderContext order);
/**
* 获取状态名称
* @return 状态名称
*/
String getStateName();
}
3.2 具体状态实现
java
/**
* 待支付状态
*/
public class PendingPaymentState implements OrderState {
@Override
public void pay(OrderContext order) {
System.out.println("✓ 支付成功,订单状态从待支付变为待发货");
order.setState(new PendingShipmentState());
}
@Override
public void ship(OrderContext order) {
throw new IllegalStateException("✗ 订单未支付,不能发货");
}
@Override
public void confirm(OrderContext order) {
throw new IllegalStateException("✗ 订单未支付,不能确认收货");
}
@Override
public void cancel(OrderContext order) {
System.out.println("✓ 订单已取消");
order.setState(new CancelledState());
}
@Override
public String getStateName() {
return "待支付";
}
}
/**
* 待发货状态
*/
public class PendingShipmentState implements OrderState {
@Override
public void pay(OrderContext order) {
System.out.println("ℹ 订单已支付,不能重复支付");
}
@Override
public void ship(OrderContext order) {
System.out.println("✓ 发货成功,订单状态从待发货变为待收货");
order.setState(new PendingReceiptState());
}
@Override
public void confirm(OrderContext order) {
throw new IllegalStateException("✗ 订单未发货,不能确认收货");
}
@Override
public void cancel(OrderContext order) {
System.out.println("✓ 订单已取消,退款处理中");
order.setState(new CancelledState());
}
@Override
public String getStateName() {
return "待发货";
}
}
/**
* 待收货状态
*/
public class PendingReceiptState implements OrderState {
@Override
public void pay(OrderContext order) {
System.out.println("ℹ 订单已完成支付");
}
@Override
public void ship(OrderContext order) {
System.out.println("ℹ 订单已发货,不能重复发货");
}
@Override
public void confirm(OrderContext order) {
System.out.println("✓ 确认收货成功,订单完成");
order.setState(new CompletedState());
}
@Override
public void cancel(OrderContext order) {
System.out.println("ℹ 订单取消申请中,请联系客服");
}
@Override
public String getStateName() {
return "待收货";
}
}
/**
* 已取消状态
*/
public class CancelledState implements OrderState {
@Override
public void pay(OrderContext order) {
System.out.println("✗ 订单已取消,不能支付");
}
@Override
public void ship(OrderContext order) {
System.out.println("✗ 订单已取消,不能发货");
}
@Override
public void confirm(OrderContext order) {
System.out.println("ℹ 订单已取消");
}
@Override
public void cancel(OrderContext order) {
System.out.println("ℹ 订单已处于取消状态");
}
@Override
public String getStateName() {
return "已取消";
}
}
/**
* 已完成状态
*/
public class CompletedState implements OrderState {
@Override
public void pay(OrderContext order) {
System.out.println("ℹ 订单已完成,无需支付");
}
@Override
public void ship(OrderContext order) {
System.out.println("✗ 订单已完成,不能发货");
}
@Override
public void confirm(OrderContext order) {
System.out.println("ℹ 订单已完成");
}
@Override
public void cancel(OrderContext order) {
System.out.println("ℹ 订单已完成,如需退货请联系客服");
}
@Override
public String getStateName() {
return "已完成";
}
}
3.3 上下文类实现
java
/**
* 订单上下文类
* 维护当前状态,并将请求委托给状态对象处理
*/
public class OrderContext {
private OrderState currentState;
private String orderId;
private String customerName;
private BigDecimal amount;
private LocalDateTime createTime;
public OrderContext(String orderId, String customerName, BigDecimal amount) {
this.orderId = orderId;
this.customerName = customerName;
this.amount = amount;
this.createTime = LocalDateTime.now();
// 初始状态为待支付
this.currentState = new PendingPaymentState();
printOrderInfo();
}
/**
* 设置新状态
*/
public void setState(OrderState state) {
this.currentState = state;
System.out.println("┌─────────────────────────────────────────┐");
System.out.println("│ 订单[" + orderId + "]状态更新:" + currentState.getStateName());
System.out.println("└─────────────────────────────────────────┘");
}
/**
* 支付
*/
public void pay() {
System.out.println("▶ 执行支付操作...");
try {
currentState.pay(this);
} catch (Exception e) {
System.err.println(" " + e.getMessage());
}
}
/**
* 发货
*/
public void ship() {
System.out.println("▶ 执行发货操作...");
try {
currentState.ship(this);
} catch (Exception e) {
System.err.println(" " + e.getMessage());
}
}
/**
* 确认收货
*/
public void confirm() {
System.out.println("▶ 执行确认收货操作...");
try {
currentState.confirm(this);
} catch (Exception e) {
System.err.println(" " + e.getMessage());
}
}
/**
* 取消订单
*/
public void cancel() {
System.out.println("▶ 执行取消订单操作...");
try {
currentState.cancel(this);
} catch (Exception e) {
System.err.println(" " + e.getMessage());
}
}
/**
* 打印订单信息
*/
private void printOrderInfo() {
System.out.println("\n┌────────────── 订单信息 ──────────────┐");
System.out.println("│ 订单号:" + orderId);
System.out.println("│ 客户:" + customerName);
System.out.println("│ 金额:¥" + amount);
System.out.println("│ 状态:" + currentState.getStateName());
System.out.println("└────────────────────────────────────┘\n");
}
public String getCurrentState() {
return currentState.getStateName();
}
}
3.4 客户端测试代码
java
import java.math.BigDecimal;
/**
* 客户端测试类
*/
public class StatePatternDemo {
public static void main(String[] args) {
System.out.println("========== 状态模式示例:订单管理系统 ==========\n");
// 创建订单1:正常流程
System.out.println("【场景1】正常购物流程");
OrderContext order1 = new OrderContext("ORD001", "张三", new BigDecimal("299.00"));
order1.pay(); // 待支付 -> 待发货
order1.ship(); // 待发货 -> 待收货
order1.confirm(); // 待收货 -> 已完成
// 创建订单2:取消流程
System.out.println("\n【场景2】支付后取消订单");
OrderContext order2 = new OrderContext("ORD002", "李四", new BigDecimal("599.00"));
order2.pay(); // 支付
order2.cancel(); // 取消(退款)
// 创建订单3:异常操作演示
System.out.println("\n【场景3】异常操作演示");
OrderContext order3 = new OrderContext("ORD003", "王五", new BigDecimal("199.00"));
order3.ship(); // 错误:未支付不能发货
order3.pay(); // 支付
order3.pay(); // 重复支付(提示)
order3.ship(); // 发货
order3.ship(); // 重复发货(提示)
order3.confirm(); // 确认收货
// 创建订单4:已完成订单操作
System.out.println("\n【场景4】已完成订单操作");
OrderContext order4 = new OrderContext("ORD004", "赵六", new BigDecimal("899.00"));
order4.pay(); // 支付
order4.ship(); // 发货
order4.confirm(); // 确认收货
order4.cancel(); // 已完成订单取消(提示联系客服)
}
}
3.5 运行结果
========== 状态模式示例:订单管理系统 ==========
【场景1】正常购物流程
┌────────────── 订单信息 ──────────────┐
│ 订单号:ORD001
│ 客户:张三
│ 金额:¥299.00
│ 状态:待支付
└────────────────────────────────────┘
▶ 执行支付操作...
✓ 支付成功,订单状态从待支付变为待发货
┌─────────────────────────────────────────┐
│ 订单[ORD001]状态更新:待发货
└─────────────────────────────────────────┘
▶ 执行发货操作...
✓ 发货成功,订单状态从待发货变为待收货
┌─────────────────────────────────────────┐
│ 订单[ORD001]状态更新:待收货
└─────────────────────────────────────────┘
▶ 执行确认收货操作...
✓ 确认收货成功,订单完成
┌─────────────────────────────────────────┐
│ 订单[ORD001]状态更新:已完成
└─────────────────────────────────────────┘
四、Spring框架中的状态模式应用
4.1 Spring StateMachine
Spring StateMachine 是 Spring 框架对状态模式的完整实现,提供了强大的状态机功能。
java
@Configuration
@EnableStateMachine
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<String, String> {
@Override
public void configure(StateMachineStateConfigurer<String, String> states)
throws Exception {
states
.withStates()
.initial("PENDING_PAYMENT")
.states(EnumSet.allOf(OrderStates.class));
}
@Override
public void configure(StateMachineTransitionConfigurer<String, String> transitions)
throws Exception {
transitions
.withExternal()
.source("PENDING_PAYMENT").target("PENDING_SHIPMENT")
.event("PAY")
.action(payAction())
.and()
.withExternal()
.source("PENDING_SHIPMENT").target("PENDING_RECEIPT")
.event("SHIP")
.action(shipAction())
.and()
.withExternal()
.source("PENDING_RECEIPT").target("COMPLETED")
.event("CONFIRM")
.action(confirmAction());
}
@Bean
public Action<String, String> payAction() {
return context -> {
System.out.println("执行支付操作...");
// 业务逻辑:扣减库存、记录日志等
context.getExtendedState().getVariables().put("paymentTime", LocalDateTime.now());
};
}
@Bean
public Action<String, String> shipAction() {
return context -> {
System.out.println("执行发货操作...");
// 业务逻辑:生成物流单号等
};
}
@Bean
public Action<String, String> confirmAction() {
return context -> {
System.out.println("执行确认收货操作...");
// 业务逻辑:完成订单、评价等
};
}
}
/**
* 订单状态枚举
*/
public enum OrderStates {
PENDING_PAYMENT, // 待支付
PENDING_SHIPMENT, // 待发货
PENDING_RECEIPT, // 待收货
COMPLETED, // 已完成
CANCELLED // 已取消
}
/**
* 订单事件枚举
*/
public enum OrderEvents {
PAY, // 支付
SHIP, // 发货
CONFIRM,// 确认收货
CANCEL // 取消
}
4.2 状态机服务层
java
@Service
public class OrderStateMachineService {
@Autowired
private StateMachineFactory<String, String> stateMachineFactory;
@Autowired
private OrderRepository orderRepository;
/**
* 创建订单状态机
*/
public StateMachine<String, String> createOrderStateMachine(String orderId) {
StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine(orderId);
stateMachine.start();
// 设置订单ID到扩展状态中
stateMachine.getExtendedState().getVariables().put("orderId", orderId);
return stateMachine;
}
/**
* 发送事件
*/
public boolean sendEvent(String orderId, String event) {
StateMachine<String, String> stateMachine = createOrderStateMachine(orderId);
return stateMachine.sendEvent(event);
}
/**
* 获取当前状态
*/
public String getCurrentState(String orderId) {
StateMachine<String, String> stateMachine = createOrderStateMachine(orderId);
return stateMachine.getState().getId();
}
/**
* 持久化状态
*/
@Transactional
public void persistState(String orderId, StateMachine<String, String> stateMachine) {
Order order = orderRepository.findById(orderId).orElseThrow();
order.setStatus(stateMachine.getState().getId());
orderRepository.save(order);
}
}
4.3 Spring Web Flow 中的状态管理
xml
<!-- order-flow.xml -->
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<!-- 初始状态:填写订单信息 -->
<view-state id="enterOrderInfo" view="orderForm">
<on-entry>
<evaluate expression="orderController.initOrder()" result="flowScope.order"/>
</on-entry>
<transition on="submit" to="validateOrder"/>
<transition on="cancel" to="cancelOrder"/>
</view-state>
<!-- 验证状态 -->
<action-state id="validateOrder">
<evaluate expression="orderValidator.validate(order)"/>
<transition on="success" to="payment"/>
<transition on="error" to="enterOrderInfo"/>
</action-state>
<!-- 支付状态 -->
<subflow-state id="payment" subflow="payment-flow">
<input name="order" value="order"/>
<transition on="paymentSuccess" to="confirmOrder"/>
<transition on="paymentFailed" to="paymentFailed"/>
</subflow-state>
<!-- 确认状态 -->
<view-state id="confirmOrder" view="confirmOrder">
<transition on="confirm" to="completeOrder"/>
<transition on="back" to="enterOrderInfo"/>
</view-state>
<!-- 结束状态 -->
<end-state id="completeOrder" view="orderComplete"/>
<end-state id="cancelOrder" view="orderCancelled"/>
<end-state id="paymentFailed" view="paymentFailed"/>
</flow>
4.4 Spring @Profile 注解的状态模式应用
java
/**
* 环境服务接口
*/
public interface EnvironmentService {
String getEnvironment();
void configure();
}
/**
* 开发环境
*/
@Component
@Profile("dev")
@ConditionalOnProperty(name = "app.env", havingValue = "development")
public class DevEnvironmentService implements EnvironmentService {
@Value("${app.debug:true}")
private boolean debug;
@Override
public String getEnvironment() {
return "Development Environment";
}
@Override
public void configure() {
System.out.println("配置开发环境...");
if (debug) {
System.out.println("调试模式已开启");
}
}
}
/**
* 生产环境
*/
@Component
@Profile("prod")
@ConditionalOnProperty(name = "app.env", havingValue = "production")
public class ProdEnvironmentService implements EnvironmentService {
@Value("${app.performance.monitoring:true}")
private boolean performanceMonitoring;
@Override
public String getEnvironment() {
return "Production Environment";
}
@Override
public void configure() {
System.out.println("配置生产环境...");
if (performanceMonitoring) {
System.out.println("性能监控已开启");
}
}
}
/**
* 测试环境
*/
@Component
@Profile("test")
public class TestEnvironmentService implements EnvironmentService {
@Override
public String getEnvironment() {
return "Test Environment";
}
@Override
public void configure() {
System.out.println("配置测试环境...");
System.out.println("测试数据准备中...");
}
}
五、状态模式的应用场景
5.1 典型应用场景
-
订单/工单系统
- 订单状态流转(待支付 → 待发货 → 待收货 → 已完成)
- 审批流程(待审批 → 审批中 → 已通过/已拒绝)
- 任务状态管理
-
工作流引擎
- BPMN流程管理
- 文档审批流程
- 请假申请流程
-
游戏开发
- 角色状态(站立、奔跑、跳跃、攻击)
- 游戏关卡状态
- AI行为状态
-
多媒体应用
- 播放器状态(播放、暂停、停止、快进)
- 录制状态
- 缓冲状态
-
网络连接
- TCP连接状态
- HTTP会话状态
- WebSocket连接状态
5.2 实际业务场景代码示例
java
/**
* 文档审批状态示例
*/
public interface DocumentState {
void submit(DocumentContext document);
void approve(DocumentContext document);
void reject(DocumentContext document);
void archive(DocumentContext document);
}
/**
* 草稿状态
*/
public class DraftState implements DocumentState {
@Override
public void submit(DocumentContext document) {
System.out.println("文档提交审批");
document.setState(new PendingApprovalState());
}
@Override
public void approve(DocumentContext document) {
System.out.println("草稿状态不能审批");
}
@Override
public void reject(DocumentContext document) {
System.out.println("草稿状态不能驳回");
}
@Override
public void archive(DocumentContext document) {
System.out.println("草稿状态不能归档");
}
}
/**
* 待审批状态
*/
public class PendingApprovalState implements DocumentState {
@Override
public void submit(DocumentContext document) {
System.out.println("文档已提交,不能重复提交");
}
@Override
public void approve(DocumentContext document) {
System.out.println("文档审批通过");
document.setState(new ApprovedState());
}
@Override
public void reject(DocumentContext document) {
System.out.println("文档审批驳回");
document.setState(new RejectedState());
}
@Override
public void archive(DocumentContext document) {
System.out.println("待审批状态不能归档");
}
}
六、状态模式 vs 策略模式
| 维度 | 状态模式 | 策略模式 |
|---|---|---|
| 目的 | 管理对象状态及其行为变化 | 封装可互换的算法 |
| 状态管理 | 内部维护状态,可自动转换 | 客户端指定策略,通常不改变 |
| 行为依赖 | 行为依赖于当前状态 | 行为由选择的策略决定 |
| 转换规则 | 包含状态转换逻辑 | 不涉及转换 |
| 适用场景 | 对象有多个状态,行为随状态变化 | 需要多种算法实现,可灵活切换 |
七、优缺点分析
优点
- 单一职责原则:将与特定状态相关的代码组织在单独的类中
- 开闭原则:添加新状态无需修改现有状态类
- 消除复杂条件语句:减少 if-else 或 switch-case 的使用
- 状态转换明确:状态间的转换逻辑集中管理,易于理解
- 提高内聚性:状态相关的行为都封装在状态类中
缺点
- 类数量增加:每个状态都需要一个具体类,增加系统复杂度
- 结构复杂化:引入更多类和接口,增加了系统抽象层次
- 学习成本:理解状态转换需要了解所有状态类
- 性能考虑:频繁的状态转换可能带来一定的性能开销
八、最佳实践建议
8.1 设计建议
- 使用枚举定义状态
java
public enum OrderStatus {
PENDING_PAYMENT("待支付"),
PENDING_SHIPMENT("待发货"),
PENDING_RECEIPT("待收货"),
COMPLETED("已完成"),
CANCELLED("已取消");
private String description;
OrderStatus(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
- 状态转换表配置
java
@Component
public class StateTransitionConfig {
private Map<OrderStatus, List<OrderStatus>> transitions;
@PostConstruct
public void init() {
transitions = new HashMap<>();
transitions.put(OrderStatus.PENDING_PAYMENT,
Arrays.asList(OrderStatus.PENDING_SHIPMENT, OrderStatus.CANCELLED));
transitions.put(OrderStatus.PENDING_SHIPMENT,
Arrays.asList(OrderStatus.PENDING_RECEIPT, OrderStatus.CANCELLED));
transitions.put(OrderStatus.PENDING_RECEIPT,
Arrays.asList(OrderStatus.COMPLETED, OrderStatus.CANCELLED));
}
public boolean isValidTransition(OrderStatus from, OrderStatus to) {
return transitions.getOrDefault(from, Collections.emptyList()).contains(to);
}
}
- 状态持久化处理
java
@Entity
@Table(name = "orders")
public class Order {
@Id
private String orderId;
@Enumerated(EnumType.STRING)
private OrderStatus status;
@Version
private Long version; // 乐观锁,防止并发修改
@Lob
@Convert(converter = StateVariablesConverter.class)
private Map<String, Object> stateVariables;
}
8.2 注意事项
- 线程安全:状态对象通常是单例的,确保无状态
- 并发控制:处理并发状态转换时的数据一致性问题
- 状态历史:记录状态变更历史便于追踪和审计
- 异常处理:定义清晰的状态转换异常体系
九、总结
状态模式是一种强大的行为型设计模式,它通过将状态相关的行为封装到独立的状态类中,使得对象能够根据内部状态的改变而改变其行为。
核心价值:
- 提供了一种优雅的方式来处理对象状态的复杂性
- 将状态转换和状态行为的逻辑分离,提高代码的可维护性
- 符合面向对象设计的开闭原则和单一职责原则
适用场景判断 :
当你的对象有以下特征时,考虑使用状态模式:
- 行为依赖于其状态,并且在运行时根据状态改变行为
- 操作中包含大量的与对象状态相关的条件语句
- 状态转换规则复杂且可能变化
- 需要在不同状态下共享相同的行为