状态模式
引言
状态模式是个能让代码在状态切换时"变身"的行为型设计模式。对象根据内部状态改变行为,就像换了个新对象。它的核心是将每个状态的逻辑封装成独立类,上下文通过持有当前状态对象来动态调整行为。相比一堆if-else或switch,状态模式让状态管理更清晰,扩展性更强。想想订单系统:从"待支付"到"已发货",每个状态都有自己的玩法,状态模式让这些切换像翻书一样自然。在企业开发中,它常用于工作流、订单处理、游戏角色等场景,帮你把复杂的状态逻辑理得明明白白。
实际开发中的用途
状态模式在需要管理明确状态和转换规则的场景中特别好使。比如电商订单(待支付 → 已支付 → 已发货),或者任务系统(待处理 → 处理中 → 已完成)。如果用条件语句硬写这些逻辑,状态一多,代码就乱成一团,维护起来跟噩梦似的。状态模式把每个状态的逻辑塞进单独的类,转换规则一目了然,改起来也方便。
举个例子:假设你在搞一个在线考试系统,试卷有"未开始""进行中""已结束"三种状态。未开始时可以改题目,进行中可以交卷,已结束只能看成绩。用状态模式,每个状态是个类,考试对象通过切换状态来改变行为。如果要加个"待批改"状态,新增一个类就行,核心代码几乎不用动,扩展性拉满。
Spring 源码中的应用
状态模式在 Spring 框架里随处可见,Spring StateMachine 是个特别典型的例子。这个框架专为复杂状态转换设计,常用于工作流、订单管理等场景。
Spring StateMachine 的核心类 DefaultStateMachine
(引用 Spring StateMachine 2.3.3,路径:org.springframework.statemachine.support.DefaultStateMachine
)是状态模式的上下文,负责持有当前状态(State
接口的实现)。状态对象定义了特定状态的行为和转换逻辑。以下是关键代码:
java
public class DefaultStateMachine<S, E> extends AbstractStateMachine<S, E> {
private State<S, E> currentState;
public DefaultStateMachine(StateMachineContext<S, E> context, State<S, E> initialState) {
this.currentState = initialState;
}
// 处理事件,触发状态切换
@Override
public void sendEvent(E event) {
State<S, E> nextState = currentState.handleEvent(event);
if (nextState != null) {
transitionTo(nextState);
}
}
// 切换状态并执行行为
private void transitionTo(State<S, E> state) {
this.currentState = state;
state.entryAction(); // 状态进入时的动作
}
}
状态模式怎么体现:
- 上下文 :
DefaultStateMachine
持有currentState
,负责状态管理。 - 状态接口 :
State<S, E>
定义了状态的行为,比如handleEvent
处理事件。 - 动态切换 :
transitionTo
切换状态,并调用新状态的entryAction
。 - 解耦 :每个状态(如
ChoiceState
)独立实现逻辑,转换规则清晰。
解决了啥:Spring StateMachine 用状态模式把状态转换逻辑从业务代码里抽出来,开发者只管定义状态和事件,框架自动处理切换。这让复杂流程的实现简单多了,维护成本也低。
Java 代码案例
下面用 Spring Boot 和 Spring StateMachine 写个电商订单状态管理的案例,展示状态模式在实际项目里的用法。订单有"待支付""已支付""已发货""已完成"四种状态,通过状态机管理转换。
代码实现
java
// 订单状态
public enum OrderState {
PENDING_PAYMENT, PAID, SHIPPED, COMPLETED
}
// 订单事件
public enum OrderEvent {
PAY, SHIP, COMPLETE, CANCEL
}
// 状态机配置
@Configuration
@EnableStateMachine
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderState, OrderEvent> {
@Override
public void configure(StateMachineStateConfigurer<OrderState, OrderEvent> states) throws Exception {
states
.withStates()
.initial(OrderState.PENDING_PAYMENT)
.states(EnumSet.allOf(OrderState.class));
}
@Override
public void configure(StateMachineTransitionConfigurer<OrderState, OrderEvent> transitions) throws Exception {
transitions
.withExternal()
.source(OrderState.PENDING_PAYMENT).target(OrderState.PAID).event(OrderEvent.PAY)
.and()
.withExternal()
.source(OrderState.PAID).target(OrderState.SHIPPED).event(OrderEvent.SHIP)
.and()
.withExternal()
.source(OrderState.SHIPPED).target(OrderState.COMPLETED).event(OrderEvent.COMPLETE)
.and()
.withExternal()
.source(OrderState.PENDING_PAYMENT).target(OrderState.PENDING_PAYMENT).event(OrderEvent.CANCEL);
}
// 状态切换日志
@Override
public void configure(StateMachineConfigurationConfigurer<OrderState, OrderEvent> config) throws Exception {
config
.withConfiguration()
.listener(new StateMachineListenerAdapter<OrderState, OrderEvent>() {
@Override
public void stateChanged(State<OrderState, OrderEvent> from, State<OrderState, OrderEvent> to) {
System.out.println("Order state changed to: " + to.getId());
}
});
}
}
// 订单服务
@Service
public class OrderService {
@Autowired
private StateMachine<OrderState, OrderEvent> stateMachine;
public void sendEvent(OrderEvent event) {
stateMachine.start();
stateMachine.sendEvent(event);
}
public OrderState getCurrentState() {
return stateMachine.getState().getId();
}
}
代码说明
- 状态模式体现 :
StateMachine
是上下文,OrderState
定义状态,OrderEvent
触发转换。转换规则在OrderStateMachineConfig
里配置,状态逻辑完全解耦。 - 解决的问题:订单状态管理通过配置实现,业务代码只管发送事件,状态机搞定切换逻辑。加新状态或事件只改配置,代码几乎不用动。
- 好处:代码清晰,状态逻辑集中,测试和维护都方便。Spring StateMachine 还支持持久化、事件监听等,适合复杂场景。
- 怎么跑 :通过
OrderService
的sendEvent
触发事件,比如PAY
事件让订单从PENDING_PAYMENT
变成PAID
,日志会记录状态变化。
总结
状态模式是个管理状态转换的狠角色,它把状态逻辑装进独立类,干掉乱七八糟的条件分支,让代码清爽又好改。在 Spring StateMachine 里,状态模式被玩得炉火纯青,DefaultStateMachine
通过切换状态对象,把复杂的状态管理变成配置游戏,订单、工作流这些场景直接起飞。我们的订单案例也证明了它的实力:配置化的状态机让业务逻辑简单明了,扩展性强,维护起来省心。
(对您有帮助 && 觉得我总结的还行) -> 受累点个免费的赞👍,谢谢