【分布式】自定义统一状态机流转设计

发布于:2025-07-01 ⋅ 阅读:(27) ⋅ 点赞:(0)


状态机用于描述一个系统在不同状态之间的转换和行为,是状态模式的一种具体应用。状态机是一种抽象的计算模型,它包含有限个状态和转换规则,用于描述系统在不同状态下如何响应输入以及在不同输入下如何进行状态转换。

一个状态机通常包含以下几个要素:

状态(States):代表系统可能处于的各种状态,例如 “已下单”、“已支付”、“已发货” 等。
事件(Events):触发状态转换的事件,例如 “下单”、“支付”、“发货” 等。
转换(Transitions):定义状态之间的转换规则,即在某个事件发生时,系统从一个状态转换到另一个状态的规则。
动作(Actions):在状态转换发生时执行的操作或行为。

一般我们在工作中,我们的主要的业务单据都会有一个状态的设计,我们会通过状态图画出他的状态流转情况,而控制这些状态如何流转,就是状态机干的事儿。

如果没有一个严格的状态机控制的话,我们是可以随便修改订单的状态的,我们可以在已下单状态直接推进到已发货状态,这显然是不对的。

而状态机就是来控制这个状态的流转的他的目的都是把状态、事件、转换以及动作封装在一起的,他把这些东西内聚在一起了。有了它,一个已下单状态的订单,只能通过支付事件来驱动,并且还会有一些其他的约束,比如支付金额>0(转移条件)等,然后他的下一个状态只能是已支付这样的。

StateMachine接口

public interface StateMachine<STATE, EVENT> {

    /**
     * 状态机转移
     *
     * @param state 状态
     * @param event 事件
     * @return
     */
    public STATE transition(STATE state, EVENT event);
}


通用状态机 BaseStateMachine

提供一个添加状态转换的方法 从state1转换到state2需要通过event事件
添加一个状态机将这个状态机放到体格map中
比如从CREATE到CONFIRM状态需要通过CONFIRM事件 在map中添加
(key: CREATE_CONFIRM value: CONFIRM)
实现transition方法 通过state和event事件得到target状态

public class BaseStateMachine<STATE, EVENT> implements StateMachine<STATE, EVENT> {
    private Map<String, STATE> stateTransitions = Maps.newHashMap();

    /**
     * 初始化状态机状态转换
     * @param origin 原状态
     * @param event 需要经过的事件
     * @param target 目标状态
     */
    protected void putTransition(STATE origin, EVENT event, STATE target) {
        stateTransitions.put(Joiner.on("_").join(origin, event), target);
    }

    @Override
    public STATE transition(STATE state, EVENT event) {
        STATE target = stateTransitions.get(Joiner.on("_").join(state, event));
        if (target == null) {
            throw new BizException("state = " + state + " , event = " + event, STATE_MACHINE_TRANSITION_FAILED);
        }
        return target;
    }
}

举例实现

状态

public enum TradeOrderState {

    /**
     * 订单创建
     */
    CREATE,

    /**
     * 订单确认
     */
    CONFIRM,
    /**
     * 已付款
     */
    PAID,
    /**
     * 交易成功
     */
    FINISH,
    /**
     * 订单关闭
     */
    CLOSED,
    /**
     * 废单,用户看不到
     */
    DISCARD;
}

事件

public enum TradeOrderEvent {

    /**
     * 订单创建
     */
    CREATE,

    /**
     * 订单确认
     */
    CONFIRM,

    /**
     * 订单创建并确认
     */
    CREATE_AND_CONFIRM,

    /**
     * 订单支付
     */
    PAY,

    /**
     * 订单取消
     */
    CANCEL,

    /**
     * 订单超时
     */
    TIME_OUT,

    /**
     * 订单完成
     */
    FINISH,

    /**
     * 订单废弃
     */
    DISCARD;
}

OrderStateMachine(BaseStateMachine实现类)

初始化一系列状态流转

public class OrderStateMachine extends BaseStateMachine<TradeOrderState, TradeOrderEvent> {

    public static final OrderStateMachine INSTANCE = new OrderStateMachine();
    

    {
        putTransition(TradeOrderState.CREATE, TradeOrderEvent.CONFIRM, TradeOrderState.CONFIRM);
        putTransition(TradeOrderState.CONFIRM, TradeOrderEvent.PAY, TradeOrderState.PAID);
        //库存预扣减成功,但是未真正扣减成功,也能支付/取消,不能因为延迟导致用户无法支付/取消。
        putTransition(TradeOrderState.CREATE, TradeOrderEvent.PAY, TradeOrderState.PAID);
        putTransition(TradeOrderState.CREATE, TradeOrderEvent.CANCEL, TradeOrderState.CLOSED);
        putTransition(TradeOrderState.CREATE, TradeOrderEvent.TIME_OUT, TradeOrderState.CLOSED);

        //订单创建过程中失败,推进到废弃态,这种状态用户看不到订单
        putTransition(TradeOrderState.CREATE, TradeOrderEvent.DISCARD, TradeOrderState.DISCARD);
        putTransition(TradeOrderState.CONFIRM, TradeOrderEvent.DISCARD, TradeOrderState.DISCARD);

        //已支付后,再确认,状态不变
        putTransition(TradeOrderState.PAID, TradeOrderEvent.CONFIRM, TradeOrderState.PAID);

        putTransition(TradeOrderState.CONFIRM, TradeOrderEvent.CANCEL, TradeOrderState.CLOSED);
        putTransition(TradeOrderState.CONFIRM, TradeOrderEvent.TIME_OUT, TradeOrderState.CLOSED);

        putTransition(TradeOrderState.PAID, TradeOrderEvent.FINISH, TradeOrderState.FINISH);
    }

}

使用

如果状态转换失败 抛出异常
如果成功 获取到转换后的状态

TradeOrderState orderState = OrderStateMachine.INSTANCE.transition(this.getOrderState(), request.getOrderEvent());

网站公告

今日签到

点亮在社区的每一天
去签到