2. 状态机与业务逻辑分离

任务目标

在订单处理系统中,状态转换逻辑与业务操作(如发送邮件、扣减库存)经常耦合在同一个方法中,导致状态机难以维护和复用。本案例的目标是将状态转换规则与业务操作分离:使用配置表驱动状态转换,业务操作通过监听器机制在状态变更时触发,从而在不修改状态机核心代码的前提下扩展业务行为。

核心设计

采用两个核心组件:状态转换配置表(声明式定义合法转换路径)和状态监听器接口(业务操作的挂载点)。状态机引擎只负责校验和推进状态,不包含任何具体业务逻辑。

完整实现

import java.util.*;

// 1. 状态与事件定义
enum OrderState {
    CREATED, PAID, SHIPPED, COMPLETED, CANCELLED
}

enum OrderEvent {
    PAY, SHIP, COMPLETE, CANCEL
}

// 2. 状态转换配置表(核心分离点)
class StateTransitionConfig {
    // key: 当前状态 + 事件 -> value: 目标状态
    private static final Map<String, OrderState> TRANSITIONS = new HashMap<>() {{
        put(key(OrderState.CREATED, OrderEvent.PAY), OrderState.PAID);
        put(key(OrderState.CREATED, OrderEvent.CANCEL), OrderState.CANCELLED);
        put(key(OrderState.PAID, OrderEvent.SHIP), OrderState.SHIPPED);
        put(key(OrderState.PAID, OrderEvent.CANCEL), OrderState.CANCELLED);
        put(key(OrderState.SHIPPED, OrderEvent.COMPLETE), OrderState.COMPLETED);
    }};

    private static String key(OrderState state, OrderEvent event) {
        return state.name() + ":" + event.name();
    }

    static Optional<OrderState> getNextState(OrderState current, OrderEvent event) {
        return Optional.ofNullable(TRANSITIONS.get(key(current, event)));
    }
}

// 3. 业务操作监听器接口(业务逻辑挂载点)
interface OrderStateListener {
    void onStateChanged(Order order, OrderState oldState, OrderState newState);
}

// 4. 订单实体
class Order {
    private String id;
    private OrderState state;
    private final List<OrderStateListener> listeners = new ArrayList<>();

    public Order(String id) {
        this.id = id;
        this.state = OrderState.CREATED;
    }

    public void addListener(OrderStateListener listener) {
        listeners.add(listener);
    }

    public OrderState getState() {
        return state;
    }

    public String getId() {
        return id;
    }

    // 5. 状态机引擎:只做转换校验与状态更新,不包含业务逻辑
    public boolean fireEvent(OrderEvent event) {
        Optional<OrderState> nextState = StateTransitionConfig.getNextState(state, event);
        if (nextState.isEmpty()) {
            return false; // 非法转换
        }
        OrderState oldState = state;
        state = nextState.get();
        // 通知所有监听器执行业务操作
        for (OrderStateListener listener : listeners) {
            listener.onStateChanged(this, oldState, state);
        }
        return true;
    }
}

// 6. 业务操作实现(与状态机完全解耦)
class OrderBusinessHandlers {
    // 业务操作1:支付后发送确认邮件
    static OrderStateListener paymentNotification = (order, oldState, newState) -> {
        if (oldState == OrderState.CREATED && newState == OrderState.PAID) {
            System.out.println("[邮件] 订单 " + order.getId() + " 支付成功通知已发送");
        }
    };

    // 业务操作2:发货后更新物流
    static OrderStateListener shippingHandler = (order, oldState, newState) -> {
        if (oldState == OrderState.PAID && newState == OrderState.SHIPPED) {
            System.out.println("[物流] 订单 " + order.getId() + " 已分配快递单号");
        }
    };

    // 业务操作3:完成订单后触发评价邀请
    static OrderStateListener completionHandler = (order, oldState, newState) -> {
        if (oldState == OrderState.SHIPPED && newState == OrderState.COMPLETED) {
            System.out.println("[评价] 订单 " + order.getId() + " 已发送评价邀请");
        }
    };
}

// 7. 最小可运行入口
public class OrderStateMachineDemo {
    public static void main(String[] args) {
        Order order = new Order("ORD-2024-001");

        // 注册业务监听器(可在运行时动态增删)
        order.addListener(OrderBusinessHandlers.paymentNotification);
        order.addListener(OrderBusinessHandlers.shippingHandler);
        order.addListener(OrderBusinessHandlers.completionHandler);

        // 执行状态流转
        System.out.println("初始状态: " + order.getState());
        System.out.println("触发支付: " + order.fireEvent(OrderEvent.PAY));
        System.out.println("当前状态: " + order.getState());
        System.out.println("触发发货: " + order.fireEvent(OrderEvent.SHIP));
        System.out.println("当前状态: " + order.getState());
        System.out.println("触发完成: " + order.fireEvent(OrderEvent.COMPLETE));
        System.out.println("当前状态: " + order.getState());

        // 验证非法转换被拒绝
        System.out.println("\n尝试从COMPLETED触发支付(非法): " + order.fireEvent(OrderEvent.PAY));
        System.out.println("状态未改变: " + order.getState());
    }
}

运行方式

# 编译并运行(无需第三方依赖)
javac OrderStateMachineDemo.java
java OrderStateMachineDemo

验证方法

程序输出应满足以下条件,即可判定实现正确:

  • 状态按 CREATED → PAID → SHIPPED → COMPLETED 顺序正确流转,每次 fireEvent 返回 true;
  • 每次状态变更后,对应监听器输出业务提示(邮件、物流、评价各一条);
  • 对 COMPLETED 状态触发 PAY 事件时返回 false,且状态保持 COMPLETED 不变,证明非法转换被配置表拦截。

预期输出

初始状态: CREATED
触发支付: true
[邮件] 订单 ORD-2024-001 支付成功通知已发送
当前状态: PAID
触发发货: true
[物流] 订单 ORD-2024-001 已分配快递单号
当前状态: SHIPPED
触发完成: true
[评价] 订单 ORD-2024-001 已发送评价邀请
当前状态: COMPLETED

尝试从COMPLETED触发支付(非法): false
状态未改变: COMPLETED

关键要点

  • 配置驱动:所有合法转换路径集中在 StateTransitionConfig 的 TRANSITIONS 映射中,新增状态或事件只需修改此表,无需改动引擎代码。
  • 业务解耦:业务操作通过 OrderStateListener 接口注入,状态机引擎不感知具体业务。新增业务(如短信通知)只需新增一个监听器实现并注册,符合开闭原则。
  • 非法转换防护:未在配置表中的状态-事件组合会被 Optional.empty() 拦截,返回 false,保证状态机状态合法性由配置统一约束。