开发可掌握的知识:基于事件驱动实现状态机

项目背景:订单状态机的自动流转

在电商、外卖、物流等系统中,订单的状态流转 是核心业务逻辑之一。例如,在电商系统中,订单可能经历以下状态:

1️⃣ NEW(待支付) → 2️⃣ PAID(已支付) → 3️⃣ SHIPPED(已发货) → 4️⃣ DELIVERED(已签收) → 5️⃣ COMPLETED(交易完成)

在实际业务中,订单状态的变化通常是由用户操作或系统事件触发,如:

  • 用户付款后,订单进入 PAID 状态
  • 商家发货后,订单进入 SHIPPED 状态
  • 用户签收后,订单进入 DELIVERED 状态
  • 系统自动确认收货,订单进入 COMPLETED 状态

在传统设计中,订单状态流转可能是:

  • 硬编码 if-else 处理状态 → 代码臃肿,不易维护
  • 数据库存储状态映射 → 需要额外查询表结构,增加复杂性
  • 手动触发每个状态 → 不能自动流转,可能导致状态遗漏

本项目的目标是:

✅ 设计 清晰、可扩展的订单状态机 ,支持 自动流转

✅ 采用 责任链模式 ,确保事件自动推进

✅ 采用 策略模式,解耦不同状态的处理逻辑

这样,我们只需要调用 handleEvent(OrderEvent.PAY),系统就能 自动执行后续所有状态转换,直到订单完成!

设计思路

1️⃣ 设计 OrderState 枚举

  • 每个订单状态(如 NEWPAID)需要:

    • 对应的处理器类 (即 OrderStateHandler 实现)
    • 触发的事件 (如 PAY 触发 PAID 状态)
  • 维护 事件到下一个状态的映射,保证状态自动流转。

2️⃣ 设计 OrderStateHandler(策略模式)

  • 不同状态执行不同逻辑 (如 支付订单、发货订单)。
  • 通过 工厂模式 动态实例化具体的 Handler

3️⃣ 设计 OrderStateMachine(责任链模式)

  • 调用 handleEvent(OrderEvent.PAY) 即可自动完成整个状态流转
  • 如果有下一个状态,就递归触发 handleEvent() ,直到完成整个订单生命周期。

1️⃣ 订单事件枚举

java 复制代码
public enum OrderEvent {
    PAY,        // 支付
    SHIP,       // 发货
    DELIVER,    // 收货
    COMPLETE    // 完成订单
}

每个 OrderState 执行完 Handler 后,发送 OrderEvent,由事件决定下一个状态


2️⃣ 订单状态枚举

java 复制代码
import java.util.HashMap;
import java.util.Map;

public enum OrderState {
    NEW(NewOrderHandler.class, OrderEvent.PAY), //待支付 -> 支付事件
    PAID(PaidOrderHandler.class, OrderEvent.SHIP), //已支付 -> 发货事件
    SHIPPED(ShippedOrderHandler.class, OrderEvent.DELIVER),  // 已发货 -> 收货事件
    DELIVERED(DeliveredOrderHandler.class, OrderEvent.COMPLETE),   //已收货 -> 完成
    COMPLETED(CompletedOrderHandler.class, null); // 终态

    private final Class<? extends OrderStateHandler> handlerClass;
    private final OrderEvent event;

    // 事件 -> 下一个状态 映射
    private static final Map<OrderEvent, OrderState> eventToNextState = new HashMap<>();

    static {
        OrderState[] states = values();
        for (int i = 0; i < states.length - 1; i++) { // 遍历除终态外的所有状态
            eventToNextState.put(states[i].event, states[i + 1]);
        }
    }

    OrderState(Class<? extends OrderStateHandler> handlerClass, OrderEvent event) {
        this.handlerClass = handlerClass;
        this.event = event;
    }

    public OrderStateHandler getHandler() {
        try {
            return handlerClass.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException("状态处理类实例化失败:" + handlerClass.getSimpleName(), e);
        }
    }

    public static OrderState getNextState(OrderEvent event) {
        return eventToNextState.get(event);
    }
}

3️⃣ 订单状态处理接口

java 复制代码
public interface OrderStateHandler {
    void handle();
}

4️⃣ 具体的状态处理类

java 复制代码
public class NewOrderHandler implements OrderStateHandler {
    public void handle() {
        System.out.println("订单已创建,等待支付...");
    }
}

public class PaidOrderHandler implements OrderStateHandler {
    public void handle() {
        System.out.println("订单已支付,准备发货...");
    }
}

public class ShippedOrderHandler implements OrderStateHandler {
    public void handle() {
        System.out.println("订单已发货,等待签收...");
    }
}

public class DeliveredOrderHandler implements OrderStateHandler {
    public void handle() {
        System.out.println("订单已签收,交易完成!");
    }
}

public class CompletedOrderHandler implements OrderStateHandler {
    public void handle() {
        System.out.println("订单已完成,流程结束!");
    }
}

5️⃣ 订单状态机

java 复制代码
public class OrderStateMachine {
    private OrderState currentState;

    public OrderStateMachine() {
        this.currentState = OrderState.NEW; // 初始状态
    }

    //事件自动流转
    public void handleEvent(OrderEvent event) {
        OrderState nextState = OrderState.getNextState(event);
        if (nextState == null) {
            System.out.println("当前状态 " + currentState + " 不支持事件:" + event);
            return;
        }

        System.out.println("状态切换到:" + nextState);
        nextState.getHandler().handle();
        this.currentState = nextState;

        // 继续触发下一个状态
        if (this.currentState != OrderState.COMPLETED && this.currentState.event != null) {
            handleEvent(this.currentState.event);
        }
    }
}

6️⃣ 测试代码

java 复制代码
public class StateMachineTest {
    public static void main(String[] args) {
        OrderStateMachine orderStateMachine = new OrderStateMachine();
        orderStateMachine.handleEvent(OrderEvent.PAY);
    }
}

✅ 运行结果

erlang 复制代码
复制编辑
状态切换到:PAID
订单已支付,准备发货...
状态切换到:SHIPPED
订单已发货,等待签收...
状态切换到:DELIVERED
订单已签收,交易完成!
状态切换到:COMPLETED
订单已完成,流程结束!

异步回调处理

新增一个 支付回调监听器,用来处理第三方支付平台的异步通知:

根据回调信息找到单号 -> 单子状态 -> 状态映射事件 ->handleEvent继续执行。

java 复制代码
public class PaymentCallbackListener {
​
    private final OrderStateMachine orderStateMachine;
​
    public PaymentCallbackListener(OrderStateMachine orderStateMachine) {
        this.orderStateMachine = orderStateMachine;
    }
​
    public void onPaymentSuccess(String orderId) {
        System.out.println("收到支付成功回调,订单ID:" + orderId);
​
        // 触发订单状态流转(支付成功)
        orderStateMachine.handleEvent(OrderEvent.PAY);
    }
}

🎯 方案亮点

优化点 设计方案
自动状态流转 只需调用 handleEvent(OrderEvent.PAY),后续状态自动执行
责任链模式 handleEvent() 递归执行,确保状态流转
策略模式 OrderStateHandler 让每个状态的业务逻辑独立
枚举映射优化 eventToNextState 确保事件映射到正确的下一个状态
避免硬编码 getHandler() 反射实例化,减少 if-else 判断

🚀 总结

这个方案实现了一个完整的状态机框架,具备自动状态流转、清晰的业务分离,并避免了 Map 关联映射的额外复杂性。

核心思路:

  1. 用枚举存储状态和事件关系 ,确保状态流转的正确性
  2. 策略模式封装不同状态的处理逻辑 ,避免 if-else 代码膨胀。
  3. 责任链模式自动推进事件 ,只需触发 PAY,即可完成整个流程。
  4. 支持扩展 :只需在 OrderState 中新增状态,就能支持新的业务需求!

这样设计,可读性强、扩展性高、易维护! 💡

相关推荐
转转技术团队26 分钟前
加Log就卡?不加Log就瞎?”——这个插件治好了我的精神
java·后端
小杜-coding1 小时前
黑马头条day02
java·spring boot·spring·spring cloud·java-ee·maven·mybatis
谦行1 小时前
前端视角 Java Web 入门手册 5.5:真实世界 Web 开发——控制反转与 @Autowired
java·后端
qw9491 小时前
JVM:JVM与Java体系结构
java·开发语言·jvm
啊QQQQQ1 小时前
设计模式-原型模式
java·设计模式·原型模式
jstart千语1 小时前
【版本控制】git命令使用大全
java·git
李白的粉1 小时前
基于ssm的航空售票系统
java·毕业设计·ssm·课程设计·源代码·航空售票系统
cg50171 小时前
Spring Boot 使用 SMB 协议
java·前端·spring boot·smb
SnXJi_1 小时前
开源技术如何助力中小企业实现财务管理自主化?
java·gitee·开源·开源软件
2401_845417452 小时前
C++ string类
java·开发语言·c++