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 通过切换状态对象,把复杂的状态管理变成配置游戏,订单、工作流这些场景直接起飞。我们的订单案例也证明了它的实力:配置化的状态机让业务逻辑简单明了,扩展性强,维护起来省心。

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

相关推荐
拾贰_C1 分钟前
【SpringBoot】MyBatisPlus(MP | 分页查询操作
java·spring boot·后端·spring·maven·apache·intellij-idea
就叫飞六吧5 小时前
Spring Security 集成指南:避免 CORS 跨域问题
java·后端·spring
冷yan~8 小时前
GitHub文档加载器设计与实现
java·人工智能·spring·ai·github·ai编程
亚林瓜子9 小时前
AWS Elastic Beanstalk部署极简Spring工程(EB CLI失败版)
spring·云计算·aws·cli·eb
小萌新~~~~9 小时前
Spark缓存---cache方法
spring·缓存·spark
软考真题app10 小时前
软件设计师考试结构型设计模式考点全解析
设计模式·软件设计师·结构型设计模式·考试考点
开开心心就好13 小时前
Word图片格式调整与转换工具
java·javascript·spring·eclipse·pdf·word·excel
xiaolin033316 小时前
【设计模式】- 行为型模式1
设计模式·状态模式·责任链模式·策略模式·命令模式·模板方法模式·行为型模式
一只码代码的章鱼16 小时前
spring -MVC-02
java·spring·mvc
沐土Arvin16 小时前
深入理解 requestIdleCallback:浏览器空闲时段的性能优化利器
开发语言·前端·javascript·设计模式·html