五维思考

学习要加,骄傲要减,机会要乘,懒惰要除。 http://www.5dthink.cn

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::

在 Spring 框架中,使用 Spring State Machine (SSM) 可以优雅地替代复杂的 if-else 状态判断逻辑。以下是完整实现方案:


1. 添加依赖

<dependency>
    <groupId>org.springframework.statemachine</groupId>
    <artifactId>spring-statemachine-starter</artifactId>
    <version>3.2.0</version> <!-- 使用最新版本 -->
</dependency>

2. 定义状态和事件枚举

public enum OrderStates {
    INIT,          // 初始状态
    WAITING_PAY,   // 待支付
    PAID,          // 已支付
    DELIVERED,     // 已发货
    RECEIVED,      // 已收货
    CANCELLED      // 已取消
}

public enum OrderEvents {
    PAY,            // 支付事件
    DELIVER,        // 发货事件
    RECEIVE,        // 收货事件
    CANCEL_PAYMENT, // 取消支付
    CANCEL_ORDER    // 取消订单
}

3. 配置状态机

@Configuration
@EnableStateMachine
public class StateMachineConfig 
    extends EnumStateMachineConfigurerAdapter<OrderStates, OrderEvents> {

    @Override
    public void configure(StateMachineStateConfigurer<OrderStates, OrderEvents> states) 
        throws Exception {
        
        states.withStates()
            .initial(OrderStates.INIT)
            .states(EnumSet.allOf(OrderStates.class))
            .end(OrderStates.RECEIVED)   // 终态:已收货
            .end(OrderStates.CANCELLED);  // 终态:已取消
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions) 
        throws Exception {
        
        transitions
            // 支付事件:从 INIT -> WAITING_PAY
            .withExternal()
                .source(OrderStates.INIT)
                .target(OrderStates.WAITING_PAY)
                .event(OrderEvents.PAY)
                .and()
            
            // 发货事件:从 PAID -> DELIVERED
            .withExternal()
                .source(OrderStates.PAID)
                .target(OrderStates.DELIVERED)
                .event(OrderEvents.DELIVER)
                .and()
            
            // 收货事件:从 DELIVERED -> RECEIVED
            .withExternal()
                .source(OrderStates.DELIVERED)
                .target(OrderStates.RECEIVED)
                .event(OrderEvents.RECEIVE)
                .and()
            
            // 取消支付:从 WAITING_PAY -> CANCELLED
            .withExternal()
                .source(OrderStates.WAITING_PAY)
                .target(OrderStates.CANCELLED)
                .event(OrderEvents.CANCEL_PAYMENT)
                .and()
            
            // 取消订单:从 INIT -> CANCELLED
            .withExternal()
                .source(OrderStates.INIT)
                .target(OrderStates.CANCELLED)
                .event(OrderEvents.CANCEL_ORDER);
    }
}

4. 添加状态监听器(处理业务逻辑)

@Component
public class OrderStateListener 
    extends StateMachineListenerAdapter<OrderStates, OrderEvents> {

    @Override
    public void transition(Transition<OrderStates, OrderEvents> transition) {
        // 状态变化时触发业务逻辑
        if (transition.getTarget().getId() == OrderStates.PAID) {
            System.out.println("订单已支付,执行库存扣减");
        } else if (transition.getTarget().getId() == OrderStates.CANCELLED) {
            System.out.println("订单取消,执行退款逻辑");
        }
    }
}

5. 使用状态机执行业务

@Service
public class OrderService {
    @Autowired
    private StateMachine<OrderStates, OrderEvents> stateMachine;

    public void payOrder() {
        // 发送支付事件
        stateMachine.sendEvent(OrderEvents.PAY);
    }

    public void cancelOrder() {
        // 发送取消事件
        stateMachine.sendEvent(OrderEvents.CANCEL_ORDER);
    }
}

6. 测试代码

@SpringBootTest
public class OrderTest {
    @Autowired
    private OrderService orderService;

    @Test
    public void testOrderFlow() {
        orderService.payOrder();    // 触发支付:INIT -> WAITING_PAY
        orderService.cancelOrder(); // 触发取消:WAITING_PAY -> CANCELLED
    }
}

优势总结

  1. 消除复杂 if-else:状态转移由配置定义,业务代码无分支判断
  2. 集中管理状态逻辑:所有状态流转规则在配置类一目了然
  3. 高扩展性:新增状态只需修改枚举和配置,无需改动业务代码
  4. 强约束性:非法状态转移会被框架自动拒绝(如从未支付直接发货)
  5. 可视化支持:可通过 stateMachine.getStates() 调试状态树

关键点:将业务状态的变化抽象为 状态(State)事件(Event),通过状态机驱动流程,彻底告别 if-else 地狱。

posted on 2025-07-12 23:47  五维思考  阅读(39)  评论(0)    收藏  举报

QQ群:1. 全栈码农【346906288】2. VBA/VSTO【2660245】