聊聊一個(gè)用 Go 實(shí)現(xiàn)的有限狀態(tài)機(jī)
easyfsm
之前看過(guò)新亮老哥的go-fsm-order,感覺(jué)還不錯(cuò)。最近在遷移項(xiàng)目的時(shí)候,發(fā)現(xiàn)有多處業(yè)務(wù)存在一些狀態(tài)的流轉(zhuǎn),所以就基于go-fsm-order做了重改,讓它可以在不同的業(yè)務(wù)場(chǎng)景下使用。
為什么不使用looplab/fsm,star挺多的啊。
不是特別喜歡,每次實(shí)例化fsm都需要重新傳遞對(duì)應(yīng)events(雖然我們可以統(tǒng)一封裝),我更期望在項(xiàng)目啟動(dòng)時(shí)把此項(xiàng)目涉及到不同業(yè)務(wù)狀態(tài)機(jī)流轉(zhuǎn)注冊(cè)到fsm,對(duì)應(yīng):不同業(yè)務(wù)->[狀態(tài)]->[事件]->處理事件主體(包含handler、params、hooks、observers等)。
這就是easyfsm的由來(lái)。
當(dāng)你開(kāi)始進(jìn)行狀態(tài)流轉(zhuǎn)時(shí),只需要:
為什么需要區(qū)分業(yè)務(wù)?
因?yàn)榻^大多數(shù)業(yè)務(wù)的狀態(tài)值都是從數(shù)據(jù)庫(kù)中獲取的,比如訂單表的訂單狀態(tài),商品表中的商品狀態(tài),有可能值是相同的。
同一個(gè)業(yè)務(wù)同一屬性對(duì)應(yīng)狀態(tài)值表達(dá)單一,不同業(yè)務(wù)下屬性狀態(tài)可能會(huì)出現(xiàn)值相同,但所表達(dá)的含義是不同的。
整體設(shè)計(jì):
簡(jiǎn)單解釋一下:
- 業(yè)務(wù):比如有商品狀態(tài)業(yè)務(wù)、訂單狀態(tài)業(yè)務(wù).....
- 狀態(tài):訂單待付款、待發(fā)貨....
- 事件:對(duì)應(yīng)狀態(tài)僅可達(dá)事件集合。比如待付款狀態(tài)的可達(dá)事件僅有:支付事件和取消事件(取決于自己的業(yè)務(wù))。
- 執(zhí)行事件主體:執(zhí)行自定義的事件函數(shù),如果有需要,還可以自定義執(zhí)行事件前后hook,事件訂閱者(比如支付事件發(fā)生后,異步通知用戶等)。
使用姿勢(shì)
首先自定義業(yè)務(wù)、狀態(tài)、事件。
自定義事件主體:
注冊(cè)到easyfsm:
開(kāi)始使用:
完整示例代碼如下:
Hook
如果想在處理事件函數(shù)的前后執(zhí)行一些hook,或者在事件執(zhí)行完畢,異步執(zhí)行一些其他業(yè)務(wù),easyfsm定義了這兩個(gè)接口。
我們可以實(shí)現(xiàn)這兩個(gè)接口:
完整代碼:
總結(jié)
上面簡(jiǎn)單介紹了下easyfsm設(shè)計(jì)以及對(duì)應(yīng)使用姿勢(shì)。
https://github.com/wuqinqiang/easyfsm