Spring + 设计模式 (十六) 行为型 - 状态模式

状态模式

引言

状态模式是个能让代码在状态切换时"变身"的行为型设计模式。对象根据内部状态改变行为,就像换了个新对象。它的核心是将每个状态的逻辑封装成独立类,上下文通过持有当前状态对象来动态调整行为。相比一堆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 通过切换状态对象,把复杂的状态管理变成配置游戏,订单、工作流这些场景直接起飞。我们的订单案例也证明了它的实力:配置化的状态机让业务逻辑简单明了,扩展性强,维护起来省心。

(对您有帮助 && 觉得我总结的还行) -> 受累点个免费的赞👍,谢谢

相关推荐
桃西西呀2 分钟前
Spring AI Alibaba 之九:我让 Agent 接着上一轮往下聊,它却只还给我一条消息,多轮记忆到底藏在哪
人工智能·spring·llm
范中勤14 分钟前
技术文档:模型工厂 `llm_provider` / `llm_use` 分层设计
设计模式·langchain·架构设计·模型工厂·llm_provider
开开心心_Every2 小时前
内存清理工具定时自动清理开机自启动
java·开发语言·spring·计算机外设·ocr·intellij-idea·excel
我是人✓2 小时前
Spring框架的事务管理
java·后端·spring
浅尝辄止;3 小时前
设计模式在HIS/LIS医疗系统中的完整实践指南(C#版)
开发语言·设计模式·c#
范中勤3 小时前
适配器模式(Adapter Pattern):原理、场景与 LLM 多厂商工程落地
设计模式·架构·langchain·适配器模式·多厂商
Wx-bishekaifayuan3 小时前
springboot线上中医药养生平台管理系统36753-计算机课程设计、毕业设计
java·spring boot·后端·spring·课程设计·express·旅游
南归北隐3 小时前
Spring AI Alibaba Graph框架实现RAG私有知识库问答
java·后端·spring·spring ai·java rag实现
乌暮4 小时前
# Spring 入门与 Spring MVC 实战指南:从零理解 IoC 到 RESTful 图书管理
java·开发语言·后端·学习·spring·mvc·restful
java资料站12 小时前
十一、Spring AI Alibaba · 高级 · 多智能体(Multi-agent)
人工智能·spring·microsoft