COLA狀態(tài)機(jī)組件實(shí)戰(zhàn):用StateMachine接口構(gòu)建復(fù)雜業(yè)務(wù)流轉(zhuǎn)系統(tǒng)

引言:狀態(tài)管理的困境與解決方案

你是否還在為業(yè)務(wù)系統(tǒng)中的狀態(tài)流轉(zhuǎn)邏輯混亂而頭疼?訂單從創(chuàng)建到支付再到發(fā)貨的狀態(tài)變化,用戶(hù)從注冊(cè)到認(rèn)證再到活躍的生命周期管理,這些復(fù)雜的狀態(tài)流轉(zhuǎn)往往導(dǎo)致代碼中充斥著大量的if-else判斷和狀態(tài)檢查,不僅難以維護(hù),還容易引發(fā)bug。

一、狀態(tài)機(jī)核心概念與COLA組件架構(gòu)

狀態(tài)機(jī)基礎(chǔ)概念

狀態(tài)機(jī)(State Machine)是一種數(shù)學(xué)模型,用于描述對(duì)象在其生命周期中的狀態(tài)變化過(guò)程。在軟件工程中,狀態(tài)機(jī)模式常用于處理具有復(fù)雜狀態(tài)轉(zhuǎn)換的業(yè)務(wù)邏輯。核心概念包括:

  • 狀態(tài)(State):對(duì)象在特定時(shí)間點(diǎn)的狀況,如訂單的"待支付"、"已支付"狀態(tài)
  • 事件(Event):觸發(fā)狀態(tài)轉(zhuǎn)換的動(dòng)作或條件,如"支付成功"事件
  • 轉(zhuǎn)換(Transition):從一個(gè)狀態(tài)到另一個(gè)狀態(tài)的變化過(guò)程
  • 動(dòng)作(Action):在狀態(tài)轉(zhuǎn)換過(guò)程中執(zhí)行的業(yè)務(wù)邏輯
  • 條件(Condition):判斷是否允許執(zhí)行某個(gè)狀態(tài)轉(zhuǎn)換的規(guī)則

二、cola-statemachine介紹

COLA框架的狀態(tài)機(jī)組件是一種輕量級(jí)的、無(wú)狀態(tài)的、基于注解的狀態(tài)機(jī)實(shí)現(xiàn),可以方便地管理訂單等業(yè)務(wù)對(duì)象的狀態(tài)轉(zhuǎn)換。COLA框架的狀態(tài)機(jī)使用了連貫接口(Fluent Interfaces)來(lái)定義狀態(tài)和事件,以及對(duì)應(yīng)的動(dòng)作和檢查。COLA框架的狀態(tài)機(jī)是COLA 4.0應(yīng)用架構(gòu)的一部分,旨在控制復(fù)雜度,提高開(kāi)發(fā)效率。

COLA框架的狀態(tài)機(jī)的優(yōu)勢(shì)有以下幾點(diǎn):

  • 簡(jiǎn)化了狀態(tài)轉(zhuǎn)換的邏輯,避免了大量的if-else判斷
  • 提高了代碼的可讀性和可維護(hù)性,方便了單元測(cè)試和重構(gòu)
  • 支持多種狀態(tài)機(jī)模式,如同步、異步、延遲等
  • 與COLA框架的其他組件協(xié)同工作,實(shí)現(xiàn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)和六邊形架構(gòu)

2.2 COLA狀態(tài)機(jī)基礎(chǔ)模型

在Cola-StateMachine組件中有如下的抽象概念模型:

  • 1.State:狀態(tài)
  • 2.Event:事件,狀態(tài)由事件觸發(fā),引起變化
  • 3.Transition:流轉(zhuǎn),表示從一個(gè)狀態(tài)到另一個(gè)狀態(tài)
  • 4.External Transition:外部流轉(zhuǎn),兩個(gè)不同狀態(tài)之間的流轉(zhuǎn)
  • 5.Internal Transition:內(nèi)部流轉(zhuǎn),同一個(gè)狀態(tài)之間的流轉(zhuǎn)
  • 6.Condition:條件,表示是否允許到達(dá)某個(gè)狀態(tài)
  • 7.Action:動(dòng)作,到達(dá)某個(gè)狀態(tài)之后,可以做什么
  • 8.StateMachine:狀態(tài)機(jī)

2.3 COLA狀態(tài)機(jī)組件架構(gòu)

COLA框架的狀態(tài)機(jī)組件(cola-component-statemachine)采用面向?qū)ο笤O(shè)計(jì),提供了靈活的狀態(tài)流轉(zhuǎn)建模能力。其核心接口關(guān)系如下:


image.png

主要接口功能說(shuō)明:

  • StateMachine:狀態(tài)機(jī)核心接口,提供事件觸發(fā)、狀態(tài)驗(yàn)證等方法
  • State:狀態(tài)接口,管理從該狀態(tài)出發(fā)的所有轉(zhuǎn)換
  • Transition:轉(zhuǎn)換接口,定義狀態(tài)間的轉(zhuǎn)換規(guī)則和行為
  • StateMachineFactory:狀態(tài)機(jī)工廠(chǎng)類(lèi),負(fù)責(zé)狀態(tài)機(jī)的注冊(cè)和獲取

2.4 Cola-StateMachine鏈路圖

image.png

三、快速入門(mén):構(gòu)建你的第一個(gè)狀態(tài)機(jī)

3.1 基本狀態(tài)機(jī)實(shí)現(xiàn)步驟

使用COLA狀態(tài)機(jī)構(gòu)建業(yè)務(wù)流轉(zhuǎn)系統(tǒng)通常遵循以下步驟:

  • 定義狀態(tài)和事件枚舉:確定業(yè)務(wù)領(lǐng)域中的狀態(tài)集合和觸發(fā)事件
  • 創(chuàng)建上下文對(duì)象:封裝狀態(tài)轉(zhuǎn)換過(guò)程中需要傳遞的數(shù)據(jù)
  • 構(gòu)建狀態(tài)機(jī):使用構(gòu)建器定義狀態(tài)間的轉(zhuǎn)換規(guī)則
  • 注冊(cè)并獲取狀態(tài)機(jī)實(shí)例:通過(guò)工廠(chǎng)類(lèi)管理狀態(tài)機(jī)
  • 觸發(fā)事件并處理結(jié)果:在業(yè)務(wù)邏輯中調(diào)用狀態(tài)機(jī)處理狀態(tài)轉(zhuǎn)換

3.2 環(huán)境準(zhǔn)備與依賴(lài)引入

要使用COLA狀態(tài)機(jī)組件,首先需要在項(xiàng)目中引入依賴(lài):

<dependency>
    <groupId>com.alibaba.cola</groupId>
    <artifactId>cola-component-statemachine</artifactId>
    <version>最新版本</version>
</dependency>

3.3 定義訂單的實(shí)體類(lèi)、訂單狀態(tài)的枚舉值、訂單事件的枚舉值

@Getter
@AllArgsConstructor
public enum OrderState {

    CREATED(0,"已創(chuàng)建"),
    PAID(1,"已支付"),
    SHIPPED(2,"已發(fā)貨"),
    DELIVERED(3,"已送達(dá)"),
    CANCELLED(4,"已取消"),
    ;

    private final Integer code;
    private final String msg;
}
@Getter
@AllArgsConstructor
public enum OrderEvent {

    PAY(0,"支付"),
    SHIP(1,"發(fā)貨"),
    DELIVER(2,"送達(dá)"),
    CANCEL(3,"取消"),
    ;

    private final Integer code;
    private final String msg;
}
@Data
@Builder
public class OrderContext {

    @ApiModelProperty("訂單ID")
    private Integer orderId;

    @ApiModelProperty("用戶(hù)ID")
    private String userId;

    @ApiModelProperty("訂單金額")
    private BigDecimal amount;

    @ApiModelProperty("備注信息")
    private String remark;

}

3.4 ColaStateMachineConfig,主要負(fù)責(zé) Cola StateMachine 的配置

public class ColaStateMachineConfig {

    public StateMachineBuilder<OrderState, OrderEvent, OrderContext> createBuilder() {
        // 3.1 創(chuàng)建狀態(tài)機(jī)構(gòu)建器
        StateMachineBuilder<OrderState, OrderEvent, OrderContext> builder =
                StateMachineBuilderFactory.create();

        // 3.2 定義狀態(tài)轉(zhuǎn)換規(guī)則
        // 已創(chuàng)建 -> 已支付 (支付事件)
        builder.externalTransition()
                .from(OrderState.CREATED)
                .to(OrderState.PAID)
                .on(OrderEvent.PAY)
                .when(checkPaymentCondition())
                .perform(updateOrderStatusAction());

        // 已支付 -> 已發(fā)貨 (發(fā)貨事件)
        builder.externalTransition()
                .from(OrderState.PAID)
                .to(OrderState.SHIPPED)
                .on(OrderEvent.SHIP)
                .when(checkStockCondition())
                .perform(createShipmentAction());

        // 已發(fā)貨 -> 已送達(dá) (送達(dá)事件)
        builder.externalTransition()
                .from(OrderState.SHIPPED)
                .to(OrderState.DELIVERED)
                .on(OrderEvent.DELIVER)
                .perform(completeOrderAction());

        // 已創(chuàng)建 -> 已取消 (取消事件)
        builder.externalTransition()
                .from(OrderState.CREATED)
                .to(OrderState.CANCELLED)
                .on(OrderEvent.CANCEL)
                .when(checkCancelCondition())
                .perform(cancelOrderAction());
        return builder;
    }
    // 條件判斷:檢查支付條件
    private static Condition<OrderContext> checkPaymentCondition() {
        return context -> {
            // 實(shí)際業(yè)務(wù)中可能檢查余額、支付方式等
            System.out.println("檢查訂單[" + context.getOrderId() + "]的支付條件");
            return context.getAmount().compareTo(BigDecimal.ZERO) > 0;
        };
    }

    // 條件判斷:檢查庫(kù)存條件
    private static Condition<OrderContext> checkStockCondition() {
        return context -> {
            // 實(shí)際業(yè)務(wù)中可能檢查商品庫(kù)存
            System.out.println("檢查訂單[" + context.getOrderId() + "]的庫(kù)存狀況");
            return true;
        };
    }

    // 條件判斷:檢查取消條件
    private static Condition<OrderContext> checkCancelCondition() {
        return context -> {
            // 實(shí)際業(yè)務(wù)中可能檢查取消時(shí)限、權(quán)限等
            System.out.println("檢查訂單[" + context.getOrderId() + "]的取消條件");
            return true;
        };
    }

    // 動(dòng)作:更新訂單狀態(tài)
    private static Action<OrderState, OrderEvent, OrderContext> updateOrderStatusAction() {
        return (from, to, event, context) -> {
            System.out.println("執(zhí)行訂單[" + context.getOrderId() + "]狀態(tài)更新: " + from + " -> " + to);
            // 實(shí)際業(yè)務(wù)中可能更新數(shù)據(jù)庫(kù)記錄、發(fā)送通知等
        };
    }

    // 動(dòng)作:創(chuàng)建物流單
    private static Action<OrderState, OrderEvent, OrderContext> createShipmentAction() {
        return (from, to, event, context) -> {
            System.out.println("為訂單[" + context.getOrderId() + "]創(chuàng)建物流單");
            // 實(shí)際業(yè)務(wù)中可能調(diào)用物流系統(tǒng)API
        };
    }

    // 動(dòng)作:完成訂單
    private static Action<OrderState, OrderEvent, OrderContext> completeOrderAction() {
        return (from, to, event, context) -> {
            System.out.println("訂單[" + context.getOrderId() + "]已完成,執(zhí)行后續(xù)處理");
            // 實(shí)際業(yè)務(wù)中可能觸發(fā)積分發(fā)放、評(píng)價(jià)提醒等
        };
    }

    // 動(dòng)作:取消訂單
    private static Action<OrderState, OrderEvent, OrderContext> cancelOrderAction() {
        return (from, to, event, context) -> {
            System.out.println("訂單[" + context.getOrderId() + "]已取消,執(zhí)行取消處理");
            // 實(shí)際業(yè)務(wù)中可能觸發(fā)退款、庫(kù)存釋放等
        };
    }
}

3.5 ColaStateMachineService,主要是封裝了狀態(tài)機(jī)的調(diào)用入口

@Service
@Slf4j
public class ColaStateMachineService {

    private static final String MACHINE_ID = "orderStateMachine";

    private StateMachine<OrderState, OrderEvent, OrderContext> stateMachine;

    @PostConstruct
    public void init() {
        ColaStateMachineConfig config = new ColaStateMachineConfig();
        StateMachineBuilder<OrderState, OrderEvent, OrderContext> stateMachineBuilder = config.createBuilder();
        // 3.3 構(gòu)建并注冊(cè)狀態(tài)機(jī)
        stateMachine = stateMachineBuilder.build(MACHINE_ID);
        //StateMachineFactory.register(stateMachine);
    }

    public String getMachineId(){
        return stateMachine.getMachineId();
    }

    public String generatePlantUML(){
        return stateMachine.generatePlantUML();
    }

    public OrderState fireEvent(OrderState source, OrderEvent event, OrderContext context) {
        return stateMachine.fireEvent(source, event, context);
    }
    public Boolean verify(OrderState source, OrderEvent event) {
        return stateMachine.verify(source, event);
    }
}

3.6 定義一個(gè) controller 的操作接口

@RequestMapping("/order")
@RestController
@Slf4j
public class OrderOperaController {

    @Resource
    private ColaStateMachineService colaStateMachineService;

    /**
     * 場(chǎng)景1-用戶(hù)支付訂單
     *
     * @return {@link Boolean}
     */
    @PostMapping("/pay")
    public Boolean pay() {
        String machineId = colaStateMachineService.getMachineId();
        System.out.println(machineId);
        OrderContext order = OrderContext.builder().orderId(1).userId("USER_123").amount(new BigDecimal("99.99")).build();
        OrderState orderState = colaStateMachineService.fireEvent(OrderState.CREATED, OrderEvent.PAY, order);
        System.out.println(orderState.toString());
        return true;
    }

    /**
     * 場(chǎng)景2-訂單發(fā)貨
     *
     * @return {@link Boolean}
     */
    @PostMapping("/ship")
    public Boolean ship() {
        String machineId = colaStateMachineService.getMachineId();
        System.out.println(machineId);
        OrderContext order = OrderContext.builder().orderId(1).userId("USER_123").amount(new BigDecimal("99.99")).build();
        OrderState orderState = colaStateMachineService.fireEvent(OrderState.PAID, OrderEvent.SHIP, order);
        System.out.println(orderState.toString());
        return true;
    }

    /**
     * 場(chǎng)景3-訂單送達(dá)
     *
     * @return {@link Boolean}
     */
    @PostMapping("/deliver")
    public Boolean deliver() {
        String machineId = colaStateMachineService.getMachineId();
        System.out.println(machineId);
        OrderContext order = OrderContext.builder().orderId(1).userId("USER_123").amount(new BigDecimal("99.99")).build();
        boolean canShip = colaStateMachineService.verify(OrderState.SHIPPED, OrderEvent.DELIVER);
        System.out.println(canShip);
        OrderState orderState = colaStateMachineService.fireEvent(OrderState.SHIPPED, OrderEvent.DELIVER, order);
        System.out.println(orderState.toString());
        return true;
    }

    /**
     * 場(chǎng)景4-檢查錯(cuò)誤關(guān)閉訂單
     *
     * @return {@link Boolean}
     */
    @PostMapping("/cancel")
    public Boolean cancel() {
        String machineId = colaStateMachineService.getMachineId();
        System.out.println(machineId);
        OrderContext order = OrderContext.builder().orderId(1).userId("USER_123").amount(new BigDecimal("99.99")).build();
        OrderState orderState = colaStateMachineService.fireEvent(OrderState.CREATED, OrderEvent.CANCEL, order);
        System.out.println(orderState.toString());
        return true;
    }
}

上述代碼定義了一個(gè)簡(jiǎn)單的訂單狀態(tài)機(jī),包含從創(chuàng)建到支付、發(fā)貨、送達(dá)的正常流程,以及從創(chuàng)建到取消的異常流程。每個(gè)狀態(tài)轉(zhuǎn)換都定義了觸發(fā)事件、前置條件和執(zhí)行動(dòng)作,使業(yè)務(wù)邏輯更加清晰和可維護(hù)。

四、COLA狀態(tài)機(jī)核心接口詳解

4.1 StateMachine接口

StateMachine接口是COLA狀態(tài)機(jī)組件的核心,定義了狀態(tài)機(jī)的基本操作:

public interface StateMachine<S, E, C> extends Visitable {
    /**
     * 驗(yàn)證事件是否可以從當(dāng)前狀態(tài)觸發(fā)
     * @param sourceStateId 當(dāng)前狀態(tài)
     * @param event 要觸發(fā)的事件
     * @return 如果可以觸發(fā)則返回true,否則返回false
     */
    boolean verify(S sourceStateId, E event);
    
    /**
     * 觸發(fā)事件并執(zhí)行狀態(tài)轉(zhuǎn)換
     * @param sourceState 源狀態(tài)
     * @param event 要觸發(fā)的事件
     * @param ctx 上下文對(duì)象
     * @return 轉(zhuǎn)換后的目標(biāo)狀態(tài)
     */
    S fireEvent(S sourceState, E event, C ctx);
    
    /**
     * 觸發(fā)并行事件,返回多個(gè)目標(biāo)狀態(tài)
     * @param sourceState 源狀態(tài)
     * @param event 要觸發(fā)的事件
     * @param ctx 上下文對(duì)象
     * @return 轉(zhuǎn)換后的多個(gè)目標(biāo)狀態(tài)列表
     */
    List<S> fireParallelEvent(S sourceState, E event, C ctx);
    
    /**
     * 獲取狀態(tài)機(jī)ID
     * @return 狀態(tài)機(jī)唯一標(biāo)識(shí)符
     */
    String getMachineId();
    
    /**
     * 顯示狀態(tài)機(jī)結(jié)構(gòu)
     */
    void showStateMachine();
    
    /**
     * 生成PlantUML描述
     * @return PlantUML格式的狀態(tài)機(jī)描述字符串
     */
    String generatePlantUML();
}

關(guān)鍵方法解析

  • verify():在實(shí)際觸發(fā)事件前驗(yàn)證轉(zhuǎn)換是否合法,避免無(wú)效的狀態(tài)轉(zhuǎn)換嘗試
  • fireEvent():核心方法,處理單一路徑的狀態(tài)轉(zhuǎn)換
  • fireParallelEvent():處理并行分支的狀態(tài)轉(zhuǎn)換,返回多個(gè)目標(biāo)狀態(tài)
  • generatePlantUML():生成可視化描述,便于狀態(tài)機(jī)結(jié)構(gòu)的理解和調(diào)試

4.2 State和Transition接口

  • State接口表示狀態(tài)機(jī)中的一個(gè)狀態(tài)節(jié)點(diǎn),管理從該狀態(tài)出發(fā)的所有轉(zhuǎn)換:
public interface State<S, E, C> extends Visitable {
    /**
     * 獲取狀態(tài)ID
     * @return 狀態(tài)標(biāo)識(shí)符
     */
    S getId();
    
    /**
     * 為狀態(tài)添加轉(zhuǎn)換規(guī)則
     * @param event 觸發(fā)事件
     * @param target 目標(biāo)狀態(tài)
     * @param transitionType 轉(zhuǎn)換類(lèi)型
     * @return 新創(chuàng)建的轉(zhuǎn)換對(duì)象
     */
    Transition<S, E, C> addTransition(E event, State<S, E, C> target, TransitionType transitionType);
    
    /**
     * 獲取指定事件的所有轉(zhuǎn)換
     * @param event 事件
     * @return 轉(zhuǎn)換列表
     */
    List<Transition<S, E, C>> getEventTransitions(E event);
    
    /**
     * 獲取該狀態(tài)的所有轉(zhuǎn)換
     * @return 轉(zhuǎn)換集合
     */
    Collection<Transition<S, E, C>> getAllTransitions();
}
  • Transition接口表示從一個(gè)狀態(tài)到另一個(gè)狀態(tài)的轉(zhuǎn)換:
public interface Transition<S, E, C> {
    /**
     * 獲取源狀態(tài)
     * @return 源狀態(tài)
     */
    State<S, E, C> getSource();
    
    /**
     * 獲取觸發(fā)事件
     * @return 事件
     */
    E getEvent();
    
    /**
     * 獲取目標(biāo)狀態(tài)
     * @return 目標(biāo)狀態(tài)
     */
    State<S, E, C> getTarget();
    
    /**
     * 獲取轉(zhuǎn)換條件
     * @return 條件對(duì)象
     */
    Condition<C> getCondition();
    
    /**
     * 獲取轉(zhuǎn)換動(dòng)作
     * @return 動(dòng)作對(duì)象
     */
    Action<S, E, C> getAction();
    
    /**
     * 執(zhí)行狀態(tài)轉(zhuǎn)換
     * @param ctx 上下文對(duì)象
     * @param checkCondition 是否檢查條件
     * @return 轉(zhuǎn)換后的目標(biāo)狀態(tài)
     */
    State<S, E, C> transit(C ctx, boolean checkCondition);
}

4.3 狀態(tài)機(jī)工廠(chǎng)與構(gòu)建器

COLA提供了StateMachineBuilder和StateMachineFactory來(lái)簡(jiǎn)化狀態(tài)機(jī)的創(chuàng)建和管理:

// 創(chuàng)建狀態(tài)機(jī)構(gòu)建器
StateMachineBuilder<OrderState, OrderEvent, OrderContext> builder = 
    StateMachineBuilderFactory.create();
 
// 構(gòu)建狀態(tài)機(jī)
StateMachine<OrderState, OrderEvent, OrderContext> stateMachine = 
    builder.build(MACHINE_ID);
 
// 注冊(cè)狀態(tài)機(jī)
StateMachineFactory.register(stateMachine);
 
// 獲取狀態(tài)機(jī)實(shí)例
StateMachine<OrderState, OrderEvent, OrderContext> orderMachine = 
    StateMachineFactory.get(MACHINE_ID);

五、復(fù)雜業(yè)務(wù)流轉(zhuǎn)場(chǎng)景實(shí)現(xiàn)

5.1 條件分支與選擇轉(zhuǎn)換

在實(shí)際業(yè)務(wù)中,常常需要根據(jù)不同條件執(zhí)行不同的狀態(tài)轉(zhuǎn)換。例如,訂單支付后根據(jù)金額大小決定后續(xù)處理流程:

// 定義訂單金額閾值
BigDecimal VIP_THRESHOLD = new BigDecimal("1000");
 
// 已支付 -> 普通處理流程 (金額 < 1000)
builder.externalTransition()
    .from(OrderState.PAID)
    .to(OrderState.PROCESSING_NORMAL)
    .on(OrderEvent.PROCESS)
    .when(ctx -> ctx.getAmount().compareTo(VIP_THRESHOLD) < 0)
    .perform(normalProcessingAction());
    
// 已支付 -> VIP處理流程 (金額 >= 1000)
builder.externalTransition()
    .from(OrderState.PAID)
    .to(OrderState.PROCESSING_VIP)
    .on(OrderEvent.PROCESS)
    .when(ctx -> ctx.getAmount().compareTo(VIP_THRESHOLD) >= 0)
    .perform(vipProcessingAction());

上述代碼中,相同的PROCESS事件根據(jù)訂單金額觸發(fā)不同的狀態(tài)轉(zhuǎn)換,實(shí)現(xiàn)了條件分支邏輯。

5.2 并行分支與合并

某些業(yè)務(wù)場(chǎng)景需要從一個(gè)狀態(tài)同時(shí)轉(zhuǎn)換到多個(gè)狀態(tài),然后在后續(xù)步驟中合并。例如,訂單支付后同時(shí)觸發(fā)物流和財(cái)務(wù)兩個(gè)并行流程:

// 并行分支示例:支付后同時(shí)觸發(fā)物流和財(cái)務(wù)流程
builder.externalParallelTransition()
    .from(OrderState.PAID)
    .toAmong(OrderState.LOGISTICS_PROCESSING, OrderState.FINANCE_PROCESSING)
    .on(OrderEvent.PROCESS)
    .when(checkParallelCondition())
    .perform(parallelProcessAction());
    
// 物流流程完成
builder.externalTransition()
    .from(OrderState.LOGISTICS_PROCESSING)
    .to(OrderState.LOGISTICS_COMPLETED)
    .on(OrderEvent.LOGISTICS_DONE)
    .perform(logisticsCompletedAction());
    
// 財(cái)務(wù)流程完成
builder.externalTransition()
    .from(OrderState.FINANCE_PROCESSING)
    .to(OrderState.FINANCE_COMPLETED)
    .on(OrderEvent.FINANCE_DONE)
    .perform(financeCompletedAction());
    
// 兩個(gè)并行流程都完成后合并
builder.externalTransitions()
    .fromAmong(OrderState.LOGISTICS_COMPLETED, OrderState.FINANCE_COMPLETED)
    .to(OrderState.ALL_PROCESSED)
    .on(OrderEvent.MERGE)
    .when(checkAllCompletedCondition())
    .perform(mergeProcessAction());

觸發(fā)并行事件并處理結(jié)果:

// 觸發(fā)并行事件
List<OrderState> parallelStates = orderMachine.fireParallelEvent(
    OrderState.PAID, OrderEvent.PROCESS, context);
    
// 輸出并行分支狀態(tài)
System.out.println("并行分支狀態(tài):");
for (OrderState state : parallelStates) {
    System.out.println("- " + state);
}
// 輸出: 
// 并行分支狀態(tài):
// - LOGISTICS_PROCESSING
// - FINANCE_PROCESSING

5.3 自循環(huán)與內(nèi)部轉(zhuǎn)換

內(nèi)部轉(zhuǎn)換(Internal Transition)是指不改變當(dāng)前狀態(tài)但執(zhí)行某些動(dòng)作的轉(zhuǎn)換,常用于狀態(tài)的自循環(huán)更新:

// 內(nèi)部轉(zhuǎn)換示例:訂單處理中超時(shí)提醒
builder.internalTransition()
    .within(OrderState.PROCESSING)
    .on(OrderEvent.REMIND)
    .when(checkProcessingTimeCondition())
    .perform(sendReminderAction());

觸發(fā)內(nèi)部轉(zhuǎn)換:

// 當(dāng)前狀態(tài)不變,但執(zhí)行提醒動(dòng)作
OrderState currentState = OrderState.PROCESSING;
OrderState newState = orderMachine.fireEvent(currentState, OrderEvent.REMIND, context);
 
System.out.println("訂單狀態(tài): " + newState);  // 輸出: 訂單狀態(tài): PROCESSING

5.4 歷史狀態(tài)與子狀態(tài)機(jī)

對(duì)于復(fù)雜業(yè)務(wù)領(lǐng)域,可以將狀態(tài)機(jī)分層設(shè)計(jì),通過(guò)歷史狀態(tài)記錄和子狀態(tài)機(jī)實(shí)現(xiàn)更高級(jí)的狀態(tài)管理:

// 定義子狀態(tài)機(jī):退款流程
StateMachine<RefundState, RefundEvent, RefundContext> refundMachine = buildRefundSubMachine();
 
// 在主狀態(tài)機(jī)中引用子狀態(tài)機(jī)
builder.externalTransition()
    .from(OrderState.PAID)
    .to(OrderState.REFUND_PROCESSING)
    .on(OrderEvent.REFUND)
    .when(checkRefundCondition())
    .perform(ctx -> {
        // 調(diào)用子狀態(tài)機(jī)處理退款流程
        RefundContext refundCtx = convertToRefundContext(ctx);
        refundMachine.fireEvent(RefundState.INITIATED, RefundEvent.PROCESS, refundCtx);
    });

六、可視化與調(diào)試

6.1 生成PlantUML狀態(tài)圖

COLA狀態(tài)機(jī)提供了generatePlantUML()方法,可以生成PlantUML格式的狀態(tài)圖描述,便于可視化和調(diào)試:

// 生成PlantUML描述
String plantUml = stateMachine.generatePlantUML();
System.out.println(plantUml);
  • 生成的PlantUML描述可以通過(guò)PlantUML工具渲染為狀態(tài)圖,例如:
@startuml
[*] --> CREATED
CREATED --> PAID : PAY
CREATED --> CANCELLED : CANCEL
PAID --> SHIPPED : SHIP
SHIPPED --> DELIVERED : DELIVER
@enduml

上述描述渲染后將顯示完整的訂單狀態(tài)流轉(zhuǎn)圖。

6.2 狀態(tài)機(jī)結(jié)構(gòu)展示

通過(guò)showStateMachine()方法可以在控制臺(tái)打印狀態(tài)機(jī)結(jié)構(gòu):

stateMachine.showStateMachine();
  • 輸出示例:
StateMachine: orderStateMachine
States:
    CREATED
        Transitions:
            On: PAY, To: PAID, Type: EXTERNAL
            On: CANCEL, To: CANCELLED, Type: EXTERNAL
    PAID
        Transitions:
            On: SHIP, To: SHIPPED, Type: EXTERNAL
    SHIPPED
        Transitions:
            On: DELIVER, To: DELIVERED, Type: EXTERNAL
    DELIVERED
    CANCELLED

七、性能優(yōu)化與最佳實(shí)踐

狀態(tài)機(jī)設(shè)計(jì)最佳實(shí)踐

  • 狀態(tài)粒度控制:狀態(tài)劃分過(guò)細(xì)會(huì)增加復(fù)雜度,過(guò)粗則失去狀態(tài)機(jī)的優(yōu)勢(shì),需找到平衡點(diǎn)
  • 單一職責(zé)原則:一個(gè)狀態(tài)機(jī)只負(fù)責(zé)一個(gè)業(yè)務(wù)領(lǐng)域的狀態(tài)流轉(zhuǎn)
  • 事件命名規(guī)范:使用動(dòng)詞或動(dòng)詞短語(yǔ)命名事件(如PAY、SHIP),清晰表達(dá)觸發(fā)動(dòng)作
  • 狀態(tài)命名規(guī)范:使用形容詞或過(guò)去分詞命名狀態(tài)(如PAID、SHIPPED),表示對(duì)象狀態(tài)

性能優(yōu)化技巧

  • 狀態(tài)機(jī)復(fù)用:通過(guò)StateMachineFactory共享狀態(tài)機(jī)實(shí)例,避免重復(fù)創(chuàng)建
  • 條件緩存:對(duì)于復(fù)雜且頻繁執(zhí)行的條件判斷,考慮添加緩存機(jī)制
  • 異步處理:對(duì)于耗時(shí)的動(dòng)作,在Action中使用異步處理模式
  • 狀態(tài)預(yù)加載:系統(tǒng)啟動(dòng)時(shí)預(yù)加載常用狀態(tài)機(jī),避免運(yùn)行時(shí)構(gòu)建開(kāi)銷(xiāo)

線(xiàn)程安全考量

COLA狀態(tài)機(jī)組件本身是線(xiàn)程安全的,可以在多線(xiàn)程環(huán)境下共享使用。但需要注意:

  • 1.上下文對(duì)象(Context)可能被多個(gè)線(xiàn)程訪(fǎng)問(wèn),需要確保其線(xiàn)程安全性
  • 2.Action中的業(yè)務(wù)邏輯應(yīng)避免共享可變狀態(tài),或采取適當(dāng)?shù)耐酱胧?br> *3. 并行觸發(fā)同一狀態(tài)機(jī)實(shí)例的不同事件是安全的,但同一業(yè)務(wù)對(duì)象的狀態(tài)轉(zhuǎn)換應(yīng)保證串行執(zhí)行

總結(jié)與展望

COLA狀態(tài)機(jī)組件通過(guò)StateMachine接口提供了一種優(yōu)雅的方式來(lái)處理復(fù)雜業(yè)務(wù)流轉(zhuǎn)邏輯,將傳統(tǒng)的if-else判斷轉(zhuǎn)換為清晰的狀態(tài)轉(zhuǎn)換規(guī)則,顯著提升了代碼的可讀性和可維護(hù)性。本文介紹的核心內(nèi)容包括:

  • 狀態(tài)機(jī)的核心概念及COLA狀態(tài)機(jī)組件的架構(gòu)設(shè)計(jì)
  • 使用StateMachine接口構(gòu)建基本狀態(tài)流轉(zhuǎn)的方法
  • 處理?xiàng)l件分支、并行流程等復(fù)雜業(yè)務(wù)場(chǎng)景的技巧
  • 狀態(tài)機(jī)的可視化調(diào)試和性能優(yōu)化策略

隨著業(yè)務(wù)復(fù)雜度的增長(zhǎng),狀態(tài)機(jī)模式的優(yōu)勢(shì)將更加明顯。未來(lái)可以進(jìn)一步探索狀態(tài)機(jī)與事件驅(qū)動(dòng)架構(gòu)(EDA)的結(jié)合,以及基于狀態(tài)機(jī)的業(yè)務(wù)流程自動(dòng)化。

通過(guò)將狀態(tài)機(jī)思想應(yīng)用到實(shí)際業(yè)務(wù)系統(tǒng)中,開(kāi)發(fā)團(tuán)隊(duì)可以構(gòu)建更加健壯、靈活且易于擴(kuò)展的業(yè)務(wù)流轉(zhuǎn)系統(tǒng),有效應(yīng)對(duì)復(fù)雜多變的業(yè)務(wù)需求。

參考:
https://gitcode.com/gh_mirrors/col/COLA
https://blog.csdn.net/gitblog_00735/article/details/151329646
https://blog.csdn.net/qq_40890575/article/details/129495003
https://segmentfault.com/a/1190000044529545

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容