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 还支持持久化、事件监听等,适合复杂场景。
  • 怎么跑 :通过 OrderServicesendEvent 触发事件,比如 PAY 事件让订单从 PENDING_PAYMENT 变成 PAID,日志会记录状态变化。

总结

状态模式是个管理状态转换的狠角色,它把状态逻辑装进独立类,干掉乱七八糟的条件分支,让代码清爽又好改。在 Spring StateMachine 里,状态模式被玩得炉火纯青,DefaultStateMachine 通过切换状态对象,把复杂的状态管理变成配置游戏,订单、工作流这些场景直接起飞。我们的订单案例也证明了它的实力:配置化的状态机让业务逻辑简单明了,扩展性强,维护起来省心。

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

相关推荐
程序猿零零漆20 小时前
Spring之旅 - 记录学习 Spring 框架的过程和经验(十一)基于XML方式、注解的声明式事务控制、Spring整合Web环境
xml·学习·spring
短剑重铸之日1 天前
《SpringBoot4.0初识》第五篇:实战代码
java·后端·spring·springboot4.0
heartbeat..1 天前
Spring MVC 全面详解(Java 主流 Web 开发框架)
java·网络·spring·mvc·web
CUIYD_19891 天前
Freemarker 无法转译 & 字符
java·开发语言·spring
柒.梧.1 天前
SSM常见核心面试问题深度解析
java·spring·面试·职场和发展·mybatis
GISer_Jing1 天前
AI:多智能体协作与记忆管理
人工智能·设计模式·aigc
雨中飘荡的记忆1 天前
责任链模式实战应用:从理论到生产实践
设计模式
麦兜*1 天前
【springboot】图文详解Spring Boot自动配置原理:为什么@SpringBootApplication是核心?
android·java·spring boot·spring·spring cloud·tomcat
廋到被风吹走1 天前
【Spring】Spring Boot Starter设计:公司级监控SDK实战指南
java·spring boot·spring
沛沛老爹1 天前
Web开发者进阶AI:Agent技能设计模式之迭代分析与上下文聚合实战
前端·人工智能·设计模式