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

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

相关推荐
RationalDysaniaer27 分钟前
Go设计模式-观察者模式
观察者模式·设计模式·golang
千千寰宇1 小时前
[设计模式/Java] 设计模式之解释器模式【27】
数据库·设计模式
麓殇⊙1 小时前
设计模式-- 原型模式详解
设计模式·原型模式
电子科技圈1 小时前
XMOS空间音频——在任何设备上都能提供3D沉浸式空间音频且实现更安全地聆听
经验分享·设计模式·性能优化·计算机外设·音视频
智想天开2 小时前
11.原型模式:思考与解读
设计模式·原型模式
XiaoLeisj2 小时前
【设计模式】深入解析代理模式(委托模式):代理模式思想、静态模式和动态模式定义与区别、静态代理模式代码实现
java·spring boot·后端·spring·设计模式·代理模式·委托模式
pwzs2 小时前
常见的 Spring Boot 注解汇总
java·spring boot·后端·spring
非ban必选3 小时前
spring-ai使用Document存储至milvus的数据结构
前端·spring·milvus
无业哥5 小时前
Mac搭建Spring5源码环境
spring
星星点点洲6 小时前
【设计模式区别】装饰器模式和适配器模式区别
设计模式·适配器模式·装饰器模式