自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

來聊聊一個輕量級的有限狀態(tài)機:Cola-StateMachine

開發(fā)
本文將用常見的下單流程演示一下 Cola-StateMachine 的基本使用,希望對你有幫助。

簡單研究了一下研究了一下市面上的幾個狀態(tài)機框架,包括但不限制于Spring Statemachine以及Cola-StateMachine,考慮到前者上下文會記錄當(dāng)前狀態(tài)機的相關(guān)屬性(當(dāng)前狀態(tài)信息、上一次狀態(tài)),對此我們就必須要通過工廠模式等方式規(guī)避這些問題,很明顯這種方案對于高并發(fā)場景下非常不友好。

于是筆者選用了更加輕量級的無狀態(tài)狀態(tài)機框架Cola-StateMachine,而本文將用常見的下單流程演示一下Cola-StateMachine的基本使用,希望對你有幫助。

一、狀態(tài)機基本概念掃盲

狀態(tài)機通俗來說就是有限狀態(tài)機(Finite-state machine,FSM),我們可以將其理解為一個數(shù)學(xué)模型,有限狀態(tài)以及這些轉(zhuǎn)臺之間轉(zhuǎn)移和動作行為的抽象的數(shù)學(xué)模型。

我們以一個簡單的開關(guān)燈為例子簡單介紹一下狀態(tài)機的基本概念,當(dāng)我們點擊開時電燈就會亮起狀態(tài)就是open,按照狀態(tài)機的幾個核心概念:

  • 當(dāng)我們準(zhǔn)備按下開關(guān)時,這個準(zhǔn)備按下開關(guān)也就是需要執(zhí)行的指令,也就是事件event。
  • 實際按下開關(guān)的執(zhí)行動作也就是狀態(tài)機中的動作(action)。
  • open就是狀態(tài)機中的狀態(tài)(state)。
  • 電燈由暗變亮,這個就是所謂transition也就是狀態(tài)的轉(zhuǎn)換,這就是狀態(tài)機的最后一個概念。

二、基于Cola-StateMachine落地下單業(yè)務(wù)

1. 業(yè)務(wù)流程說明

現(xiàn)在我們就以一個訂單為例子介紹一下狀態(tài)機的進階使用,如下圖:

  • 初始狀態(tài)下訂單狀態(tài)為待支付。
  • 用戶點擊付款之后會觸發(fā)已付款事件。
  • 此時訂單的狀態(tài)就會變?yōu)榇l(fā)貨。
  • 商家完成發(fā)貨之后觸發(fā)已發(fā)貨事件,此時訂單變?yōu)榇肇洝?/li>
  • 最終,買家收獲之后觸發(fā)已收貨事件,訂單變?yōu)榻K態(tài)已完成。

2. 狀態(tài)機落地

基于上述需求我們進行代碼落地,首先定義訂單狀態(tài)枚舉,代碼如下所示,該枚舉將交由后續(xù)狀態(tài)機進行狀態(tài)扭轉(zhuǎn)的和事件的映射配置:

public enum OrderStatusEnum {
    WAIT_PAYMENT(0, "待支付"),
    WAIT_DELIVER(1, "待發(fā)貨"),
    WAIT_RECEIVE(2, "待收貨"),
    FINISH(3, "完成");

    private int code;
    private String description;

    OrderStatusEnum(int code, String description) {
        this.code = code;
        this.description = description;
    }
 //get set......

}

然后就是事件枚舉,如上圖所說,筆者分別定義了買家已支付事件、商家已發(fā)貨事件和買家已收貨的3個事件枚舉:

public enum OrderEventEnum {

    PAYED(0,"已支付"),
    DELIVERY(1,"已發(fā)貨"),
    RECEIVED(2,"已收貨");

    private int code;
    private String description;

    OrderEventEnum(int code, String description) {
        this.code = code;
        this.description = description;
    }
 //get set ......
}

為了簡潔且方便的演示實際業(yè)務(wù)持久化的場景,筆者通過一個ConcurrentHashMap模擬數(shù)據(jù)庫存儲:

@Component
public class OrderMapper {
    private Map<Long, Order> orders = new ConcurrentHashMap<>();

    public void put(Long id, Order order) {
        orders.put(id, order);
    }

    public Order get(Long id) {
        return orders.get(id);
    }

    public Map<Long, Order> getOrders() {
        return orders;
    }
}

重點來了,接下來就是訂單狀態(tài)扭轉(zhuǎn)和事件的綁定,這里筆者簡單說明一下,Cola-StateMachine進行配置初始化時,是通過內(nèi)置的StateMachineBuilderFactory進行創(chuàng)建。

我們指明狀態(tài)和事件類型為上文所述的OrderStatusEnum和OrderEventEnum,以及實際操作的對象是訂單類order,通過externalTransition進行對應(yīng)狀態(tài)扭轉(zhuǎn)和事件配置。

我們以第一條配置為例,當(dāng)我們觸發(fā)PAYED即買家已支付事件時,狀態(tài)會從WAIT_PAYMENT待支付變?yōu)榇l(fā)貨WAIT_DELIVER,同時為了明確我們的訂單是否是由待支付變?yōu)榇l(fā)貨,筆者通過when函數(shù)校驗一下對訂單狀態(tài)進行了一下校驗。

明確之后狀態(tài)源狀態(tài)是待支付之后,這條配置執(zhí)行perform的動作(Action),即將訂單狀態(tài)改為待發(fā)貨,然后將訂單最新的狀態(tài)持久化入庫。

而其他配置同理,讀者可參考注釋自行了解:

@Component
public class OrderStatusMachineConfig {

    @Autowired
    private OrderMapper orderMapper;

    @Bean
    public StateMachine stateMachine() {
        StateMachineBuilder<OrderStatusEnum, OrderEventEnum, Order> builder = StateMachineBuilderFactory.create();
        builder.externalTransition()
                .from(OrderStatusEnum.WAIT_PAYMENT)//從待支付
                .to(OrderStatusEnum.WAIT_DELIVER)//變?yōu)榇l(fā)貨
                .on(OrderEventEnum.PAYED)//需要通過支付事件
                .when(o -> o.getOrderStatus().equals(OrderStatusEnum.WAIT_PAYMENT))//判斷條件為傳入的訂單是待支付的
                .perform((f, t, e, o) -> {
                    System.out.println("將" + JSONUtil.toJsonStr(o) + " 由狀態(tài) " + f.getDescription() + " 變?yōu)?" + t.getDescription());
                    //上述要求符合后執(zhí)行將狀態(tài)修改為代發(fā)貨,并持久化
                    o.setOrderStatus(OrderStatusEnum.WAIT_DELIVER);
                    orderMapper.put(o.getOrderId(), o);
                });


        builder.externalTransition()
                .from(OrderStatusEnum.WAIT_DELIVER)//從待發(fā)貨
                .to(OrderStatusEnum.WAIT_RECEIVE)//變?yōu)榇斋@
                .on(OrderEventEnum.DELIVERY)//通過發(fā)貨事件
                .when(o -> true)//沒有需要考慮的條件
                .perform((f, t, e, o) -> {//修改訂單狀態(tài)并持久化入庫
                    o.setOrderStatus(OrderStatusEnum.WAIT_RECEIVE);
                    orderMapper.put(o.getOrderId(), o);
                    System.out.println("將" + JSONUtil.toJsonStr(o) + " 由狀態(tài) " + f.getDescription() + " 變?yōu)?" + t.getDescription());
                });

        builder.externalTransition()
                .from(OrderStatusEnum.WAIT_RECEIVE)//從待收貨
                .to(OrderStatusEnum.FINISH)//到已完成
                .on(OrderEventEnum.RECEIVED)//通過收獲事件觸發(fā)
                .when(o -> true)//無需任何條件校驗
                .perform((f, t, e, o) -> {
                    //修改狀態(tài)并持久化
                    o.setOrderStatus(OrderStatusEnum.FINISH);
                    orderMapper.put(o.getOrderId(), o);
                    System.out.println("將" + JSONUtil.toJsonStr(o) + " 由狀態(tài) " + f.getDescription() + " 變?yōu)?" + t.getDescription());
                });

        return builder.build("orderStateMachine");
    }

}

完成上述配置后,我們就可以在業(yè)務(wù)代碼上使用這套狀態(tài)機了,我們在開發(fā)買家支付方法時,只需將狀態(tài)機注入,然后調(diào)用狀態(tài)機的fireEvent方法,傳入訂單的源狀態(tài)、事件枚舉、訂單信息,讓狀態(tài)機根據(jù)我們的狀態(tài)和事件進行判斷,并完成狀態(tài)修改和持久化:

對應(yīng)代碼如下,讀者參考注釋閱讀:

@Service
public class OrderService {

    @Autowired
    StateMachine<OrderStatusEnum, OrderEventEnum, Order> stateMachine;

    private AtomicLong id = new AtomicLong(0);
    @Autowired
    private OrderMapper orderMapper;


    public Order create() {
        //創(chuàng)建訂單
        Order order = new Order();
        //初始化狀態(tài)為待支付
        order.setOrderStatus(OrderStatusEnum.WAIT_PAYMENT);
        //分配id
        order.setOrderId(id.incrementAndGet());
        orderMapper.put(order.getOrderId(), order);

        System.out.println("訂單創(chuàng)建成功:" + JSONUtil.toJsonStr(order));

        return order;
    }


    public void pay(long id) {
        //查詢訂單
        Order order = orderMapper.get(id);
        System.out.println("準(zhǔn)備下單,訂單號:" + id);
        //生成事件消息,希望將訂單狀態(tài)改為已支付,并存入當(dāng)前訂單數(shù)據(jù)
        stateMachine.fireEvent(order.getOrderStatus(), OrderEventEnum.PAYED, order);

    }


    public void deliver(long id) {
        Order order = orderMapper.get(id);
        System.out.println("準(zhǔn)備給訂單發(fā)貨,訂單號:" + id);
        //傳入訂單,并觸發(fā)發(fā)貨事件,成功后訂單狀態(tài)會改為待收貨
        stateMachine.fireEvent(order.getOrderStatus(), OrderEventEnum.DELIVERY, order);
    }


    public void receive(long id) {
        Order order = orderMapper.get(id);
        System.out.println("嘗試收貨,訂單號:" + id);
        //傳入訂單,并觸發(fā)收貨事件,將訂單修改為已完成
        stateMachine.fireEvent(order.getOrderStatus(), OrderEventEnum.RECEIVED, order);
    }

    public Map<Long, Order> getOrders() {
        return orderMapper.getOrders();
    }


}

3. 最終效果演示

最后我們給出并發(fā)的測試用例:

CountDownLatch countDownLatch = new CountDownLatch(2);
        new Thread(() -> {
            orderService.create();
            orderService.pay(1L);
            orderService.deliver(1L);
            orderService.receive(1L);
            countDownLatch.countDown();
        }).start();


        new Thread(() -> {
            orderService.create();
            orderService.pay(2L);
            orderService.deliver(2L);
            orderService.receive(2L);
            countDownLatch.countDown();
        }).start();
        countDownLatch.await();

        System.out.println("訂單處理完成:" + JSONUtil.toJsonStr(orderService.getOrders()));

可以看到訂單都完成了:

訂單創(chuàng)建成功:{"orderId":1,"orderStatus":"WAIT_PAYMENT"}
訂單創(chuàng)建成功:{"orderId":2,"orderStatus":"WAIT_PAYMENT"}
準(zhǔn)備下單,訂單號:1
準(zhǔn)備下單,訂單號:2
將{"orderId":1,"orderStatus":"WAIT_PAYMENT"} 由狀態(tài) 待支付 變?yōu)?待發(fā)貨
將{"orderId":2,"orderStatus":"WAIT_PAYMENT"} 由狀態(tài) 待支付 變?yōu)?待發(fā)貨
準(zhǔn)備給訂單發(fā)貨,訂單號:1
準(zhǔn)備給訂單發(fā)貨,訂單號:2
將{"orderId":1,"orderStatus":"WAIT_RECEIVE"} 由狀態(tài) 待發(fā)貨 變?yōu)?待收貨
將{"orderId":2,"orderStatus":"WAIT_RECEIVE"} 由狀態(tài) 待發(fā)貨 變?yōu)?待收貨
嘗試收貨,訂單號:2
嘗試收貨,訂單號:1
將{"orderId":2,"orderStatus":"FINISH"} 由狀態(tài) 待收貨 變?yōu)?完成
將{"orderId":1,"orderStatus":"FINISH"} 由狀態(tài) 待收貨 變?yōu)?完成
訂單處理完成:{"1":{"orderId":1,"orderStatus":"FINISH"},"2":{"orderId":2,"orderStatus":"FINISH"}}

三、小結(jié)

自此我們通過Cola-StateMachine完成一個簡單的案例快速入門了狀態(tài)機的使用,希望對你有幫助。

責(zé)任編輯:趙寧寧 來源: 寫代碼的SharkChili
相關(guān)推薦

2024-01-08 09:46:47

2022-03-06 19:57:50

狀態(tài)機easyfsm項目

2013-09-03 09:57:43

JavaScript有限狀態(tài)機

2021-04-29 09:31:05

前端開發(fā)技術(shù)

2021-09-07 06:40:26

狀態(tài)機識別地址

2014-05-21 11:09:56

前端有限狀態(tài)機

2019-12-13 19:00:26

PekwmLinux桌面

2023-04-12 07:14:31

Spring應(yīng)用業(yè)務(wù)

2022-06-06 22:23:26

Tina工具Markdown

2023-06-28 08:16:50

Autofac應(yīng)用程序

2021-10-27 11:29:32

框架Web開發(fā)

2025-04-14 09:30:11

Spring狀態(tài)機訂單

2021-07-08 09:15:20

單片機編程狀態(tài)機編程語言

2021-01-05 08:35:24

GNU nanoVim編輯器

2023-03-06 07:35:30

狀態(tài)機工具訂單狀態(tài)

2025-01-09 08:00:00

Fluxy文件傳輸

2022-08-31 12:48:48

TinyDBPython數(shù)據(jù)庫

2020-08-27 11:39:05

JavaRESTful Web編程語言

2023-02-27 09:49:31

Java開發(fā)工具

2017-10-11 16:12:19

內(nèi)存
點贊
收藏

51CTO技術(shù)棧公眾號