Go語言狀態(tài)機(jī)的實(shí)現(xiàn)
一、狀態(tài)機(jī)
1. 定義
有限狀態(tài)機(jī)(Finite-state machine, FSM),簡稱狀態(tài)機(jī),是表示有限個(gè)狀態(tài)以及在這些狀態(tài)之間的轉(zhuǎn)移和動作等行為的數(shù)學(xué)模型。
2. 組成要素
- 現(xiàn)態(tài)(src state):事務(wù)當(dāng)前所處的狀態(tài)。
- 事件(event):事件就是執(zhí)行某個(gè)操作的觸發(fā)條件,當(dāng)一個(gè)事件被滿足,將會觸發(fā)一個(gè)動作,或者執(zhí)行一次狀態(tài)的遷移。
- 動作(action):事件滿足后執(zhí)行的動作。動作執(zhí)行完畢后,可以遷移到新的狀態(tài),也可以仍舊保持原狀態(tài)。動作不是必需的,當(dāng)事件滿足后,也可以不執(zhí)行任何動作,直接遷移到新狀態(tài)。
- 次態(tài)(dst state):事件滿足后要遷往的新狀態(tài)。“次態(tài)”是相對于“現(xiàn)態(tài)”而言的,“次態(tài)”一旦被激活,就轉(zhuǎn)變成新的“現(xiàn)態(tài)”了。
- 狀態(tài)流轉(zhuǎn)(transition):事物從現(xiàn)態(tài)轉(zhuǎn)為次態(tài)的整個(gè)過程。
3. 優(yōu)點(diǎn)
- 代碼抽象:將業(yè)務(wù)流程進(jìn)行抽象和結(jié)構(gòu)化,將復(fù)雜的狀態(tài)轉(zhuǎn)移圖,分割成相鄰狀態(tài)的最小單元。這樣相當(dāng)于搭建樂高積木,在這套機(jī)制上可以組合成復(fù)雜的狀態(tài)轉(zhuǎn)移圖,同時(shí)隱藏了系統(tǒng)的復(fù)雜度。
- 簡化流程:業(yè)務(wù)rd只需要關(guān)注當(dāng)前操作的業(yè)務(wù)邏輯(狀態(tài)流轉(zhuǎn)過程中的業(yè)務(wù)回調(diào)函數(shù)),極大的解耦了狀態(tài)和業(yè)務(wù)。
- 易擴(kuò)展:在新增狀態(tài)或事件時(shí),無需修改原有的狀態(tài)流轉(zhuǎn)邏輯,直接建立新的狀態(tài)轉(zhuǎn)移鏈路即可。
- 業(yè)務(wù)建模:通過最小粒度的相鄰狀態(tài)拼接,最終組成了業(yè)務(wù)的整體graph。
二、代碼
假設(shè)我們有要實(shí)現(xiàn)一個(gè)訂單下單功能,上圖是訂單狀態(tài)的流轉(zhuǎn)圖,方框?yàn)橛唵蔚臓顟B(tài),箭頭旁的文字為事件。
1. database包
package database import "fmt" // DB 模擬數(shù)據(jù)庫對象 type DB struct { } // Transaction 模擬事務(wù) func (db *DB) Transaction(fun func() error) error { ?? ?fmt.Println("事務(wù)執(zhí)行開始。") ?? ?err := fun() ?? ?fmt.Println("事務(wù)執(zhí)行結(jié)束。") ?? ?return err } // Order 訂單 type Order struct { ?? ?ID ? ?int64 // 主鍵ID ?? ?State int ? // 狀態(tài) } type OrderList []*Order // 查詢所有訂單 func ListAllOrder() (OrderList, error) { ?? ?orderList := OrderList{ ?? ??? ?&Order{1, 0}, ?? ??? ?&Order{2, 1}, ?? ??? ?&Order{2, 2}, ?? ?} ?? ?return orderList, nil } // UpdateOrderState 更新訂單狀態(tài) func UpdateOrderState(curOrder *Order, srcState int, dstState int) error { ?? ?if curOrder.State == srcState { ?? ??? ?curOrder.State = dstState ?? ?} ?? ?fmt.Printf("更新id為 %v 的訂單狀態(tài),從現(xiàn)態(tài)[%v]到次態(tài)[%v]\n", curOrder.ID, srcState, dstState) ?? ?return nil }
用來模擬數(shù)據(jù)庫的操作,如數(shù)據(jù)庫事務(wù)、查詢所有訂單、更新訂單狀態(tài)等。
2. fsm包
package fsm import ( ?? ?"fmt" ?? ?"reflect" ?? ?"zuzhiang/database" ) // FSMState 狀態(tài)機(jī)的狀態(tài)類型 type FSMState int // FSMEvent 狀態(tài)機(jī)的事件類型 type FSMEvent string // FSMTransitionMap 狀態(tài)機(jī)的狀態(tài)轉(zhuǎn)移圖類型,現(xiàn)態(tài)和事件一旦確定,次態(tài)和動作就唯一確定 type FSMTransitionMap map[FSMState]map[FSMEvent]FSMDstStateAndAction // FSMTransitionFunc 狀態(tài)機(jī)的狀態(tài)轉(zhuǎn)移函數(shù)類型 type FSMTransitionFunc func(params map[string]interface{}, srcState FSMState, dstState FSMState) error // FSMDstStateAndAction 狀態(tài)機(jī)的次態(tài)和動作 type FSMDstStateAndAction struct { ?? ?DstState FSMState ?// 次態(tài) ?? ?Action ? FSMAction // 動作 } // FSMAction 狀態(tài)機(jī)的動作 type FSMAction interface { ?? ?Before(bizParams map[string]interface{}) error ? ? ? ? ? ? ? ? ? // 狀態(tài)轉(zhuǎn)移前執(zhí)行 ?? ?Execute(bizParams map[string]interface{}, tx *database.DB) error // 狀態(tài)轉(zhuǎn)移中執(zhí)行 ?? ?After(bizParams map[string]interface{}) error ? ? ? ? ? ? ? ? ? ?// 狀態(tài)轉(zhuǎn)移后執(zhí)行 } // FSM 狀態(tài)機(jī),元素均為不可導(dǎo)出 type FSM struct { ?? ?transitionMap ?FSMTransitionMap ?// 狀態(tài)轉(zhuǎn)移圖 ?? ?transitionFunc FSMTransitionFunc // 狀態(tài)轉(zhuǎn)移函數(shù) } // CreateNewFSM 創(chuàng)建一個(gè)新的狀態(tài)機(jī) func CreateNewFSM(transitionFunc FSMTransitionFunc) *FSM { ?? ?return &FSM{ ?? ??? ?transitionMap: ?make(FSMTransitionMap), ?? ??? ?transitionFunc: transitionFunc, ?? ?} } // SetTransitionMap 設(shè)置狀態(tài)機(jī)的狀態(tài)轉(zhuǎn)移圖 func (fsm *FSM) SetTransitionMap(srcState FSMState, event FSMEvent, dstState FSMState, action FSMAction) { ?? ?if int(srcState) < 0 || len(event) <= 0 || int(dstState) < 0 { ?? ??? ?panic("現(xiàn)態(tài)|事件|次態(tài)非法。") ?? ??? ?return ?? ?} ?? ?transitionMap := fsm.transitionMap ?? ?if transitionMap == nil { ?? ??? ?transitionMap = make(FSMTransitionMap) ?? ?} ?? ?if _, ok := transitionMap[srcState]; !ok { ?? ??? ?transitionMap[srcState] = make(map[FSMEvent]FSMDstStateAndAction) ?? ?} ?? ?if _, ok := transitionMap[srcState][event]; !ok { ?? ??? ?dstStateAndAction := FSMDstStateAndAction{ ?? ??? ??? ?DstState: dstState, ?? ??? ??? ?Action: ? action, ?? ??? ?} ?? ??? ?transitionMap[srcState][event] = dstStateAndAction ?? ?} else { ?? ??? ?fmt.Printf("現(xiàn)態(tài)[%v]+事件[%v]+次態(tài)[%v]已定義過,請勿重復(fù)定義。\n", srcState, event, dstState) ?? ??? ?return ?? ?} ?? ?fsm.transitionMap = transitionMap } // Push 狀態(tài)機(jī)的狀態(tài)遷移 func (fsm *FSM) Push(tx *database.DB, params map[string]interface{}, currentState FSMState, event FSMEvent) error { ?? ?// 根據(jù)現(xiàn)態(tài)和事件從狀態(tài)轉(zhuǎn)移圖獲取次態(tài)和動作 ?? ?transitionMap := fsm.transitionMap ?? ?events, eventExist := transitionMap[currentState] ?? ?if !eventExist { ?? ??? ?return fmt.Errorf("現(xiàn)態(tài)[%v]未配置遷移事件", currentState) ?? ?} ?? ?dstStateAndAction, ok := events[event] ?? ?if !ok { ?? ??? ?return fmt.Errorf("現(xiàn)態(tài)[%v]+遷移事件[%v]未配置次態(tài)", currentState, event) ?? ?} ?? ?dstState := dstStateAndAction.DstState ?? ?action := dstStateAndAction.Action ?? ?// 執(zhí)行before方法 ?? ?if action != nil { ?? ??? ?fsmActionName := reflect.ValueOf(action).String() ?? ??? ?fmt.Printf("現(xiàn)態(tài)[%v]+遷移事件[%v]->次態(tài)[%v], [%v].before\n", currentState, event, dstState, fsmActionName) ?? ??? ?if err := action.Before(params); err != nil { ?? ??? ??? ?return fmt.Errorf("現(xiàn)態(tài)[%v]+遷移事件[%v]->次態(tài)[%v]失敗, [%v].before, err: %v", currentState, event, dstState, fsmActionName, err) ?? ??? ?} ?? ?} ?? ?// 事務(wù)執(zhí)行execute方法和transitionFunc ?? ?if tx == nil { ?? ??? ?tx = new(database.DB) ?? ?} ?? ?transactionErr := tx.Transaction(func() error { ?? ??? ?fsmActionName := reflect.ValueOf(action).String() ?? ??? ?fmt.Printf("現(xiàn)態(tài)[%v]+遷移事件[%v]->次態(tài)[%v], [%v].execute\n", currentState, event, dstState, fsmActionName) ?? ??? ?if action != nil { ?? ??? ??? ?if err := action.Execute(params, tx); err != nil { ?? ??? ??? ??? ?return fmt.Errorf("狀態(tài)轉(zhuǎn)移執(zhí)行出錯(cuò):%v", err) ?? ??? ??? ?} ?? ??? ?} ?? ??? ?fmt.Printf("現(xiàn)態(tài)[%v]+遷移事件[%v]->次態(tài)[%v], transitionFunc\n", currentState, event, dstState) ?? ??? ?if err := fsm.transitionFunc(params, currentState, dstState); err != nil { ?? ??? ??? ?return fmt.Errorf("執(zhí)行狀態(tài)轉(zhuǎn)移函數(shù)出錯(cuò): %v", err) ?? ??? ?} ?? ??? ?return nil ?? ?}) ?? ?if transactionErr != nil { ?? ??? ?return transactionErr ?? ?} ?? ?// 執(zhí)行after方法 ?? ?if action != nil { ?? ??? ?fsmActionName := reflect.ValueOf(action).String() ?? ??? ?fmt.Printf("現(xiàn)態(tài)[%v]+遷移事件[%v]->次態(tài)[%v], [%v].after\n", currentState, event, dstState, fsmActionName) ?? ??? ?if err := action.After(params); err != nil { ?? ??? ??? ?return fmt.Errorf("現(xiàn)態(tài)[%v]+遷移事件[%v]->次態(tài)[%v]失敗, [%v].before, err: %v", currentState, event, dstState, fsmActionName, err) ?? ??? ?} ?? ?} ?? ?return nil }
狀態(tài)機(jī)包含的元素有兩個(gè):狀態(tài)轉(zhuǎn)移圖和狀態(tài)轉(zhuǎn)移函數(shù),為了防止包外直接調(diào)用,這兩個(gè)元素都設(shè)為了不可導(dǎo)出的。狀態(tài)轉(zhuǎn)移圖說明了狀態(tài)機(jī)的狀態(tài)流轉(zhuǎn)情況,狀態(tài)轉(zhuǎn)移函數(shù)定義了在狀態(tài)轉(zhuǎn)移的過程中需要做的事情,在創(chuàng)建狀態(tài)時(shí)指定,如更新數(shù)據(jù)庫實(shí)體(order)的狀態(tài)。
而狀態(tài)轉(zhuǎn)移圖又包含現(xiàn)態(tài)、事件、次態(tài)和動作,一旦現(xiàn)態(tài)和事件確定,那么狀態(tài)流轉(zhuǎn)的唯一次態(tài)和動作就隨之確定。
狀態(tài)機(jī)的動作又包含三個(gè):Before、Execute和After。Before操作在是事務(wù)前執(zhí)行,由于此時(shí)沒有翻狀態(tài),所以該步可能會被重復(fù)執(zhí)行。Execute操作是和狀態(tài)轉(zhuǎn)移函數(shù)在同一事務(wù)中執(zhí)行的,同時(shí)成功或同時(shí)失敗。After操作是在事務(wù)后執(zhí)行,因?yàn)樵趫?zhí)行前狀態(tài)已經(jīng)翻轉(zhuǎn),所以最多會執(zhí)行一次,在業(yè)務(wù)上允許執(zhí)行失敗或未執(zhí)行。
狀態(tài)機(jī)的主要方法有兩個(gè),SetTransitionMap方法用來設(shè)置狀態(tài)機(jī)的狀態(tài)轉(zhuǎn)移圖,Push方法用來根據(jù)現(xiàn)態(tài)和事件推動狀態(tài)機(jī)進(jìn)行狀態(tài)翻轉(zhuǎn)。Push方法中會先執(zhí)行Before動作,再在同一事務(wù)中執(zhí)行Execute動作和狀態(tài)轉(zhuǎn)移函數(shù),最后執(zhí)行After動作。在執(zhí)行Push方法的時(shí)候會將params參數(shù)傳遞給狀態(tài)轉(zhuǎn)移函數(shù)。
3. order包
(1) order
package order import ( ?? ?"fmt" ?? ?"zuzhiang/database" ?? ?"zuzhiang/fsm" ) var ( ?? ?// 狀態(tài) ?? ?StateOrderInit ? ? ? ? ?= fsm.FSMState(0) // 初始狀態(tài) ?? ?StateOrderToBePaid ? ? ?= fsm.FSMState(1) // 待支付 ?? ?StateOrderToBeDelivered = fsm.FSMState(2) // 待發(fā)貨 ?? ?StateOrderCancel ? ? ? ?= fsm.FSMState(3) // 訂單取消 ?? ?StateOrderToBeReceived ?= fsm.FSMState(4) // 待收貨 ?? ?StateOrderDone ? ? ? ? ?= fsm.FSMState(5) // 訂單完成 ?? ?// 事件 ?? ?EventOrderPlace ? ? ?= fsm.FSMEvent("EventOrderPlace") ? ? ?// 下單 ?? ?EventOrderPay ? ? ? ?= fsm.FSMEvent("EventOrderPay") ? ? ? ?// 支付 ?? ?EventOrderPayTimeout = fsm.FSMEvent("EventOrderPayTimeout") // 支付超時(shí) ?? ?EventOrderDeliver ? ?= fsm.FSMEvent("EventOrderDeliver") ? ?// 發(fā)貨 ?? ?EventOrderReceive ? ?= fsm.FSMEvent("EventOrderReceive") ? ?// 收貨 ) var orderFSM *fsm.FSM // orderTransitionFunc 訂單狀態(tài)轉(zhuǎn)移函數(shù) func orderTransitionFunc(params map[string]interface{}, srcState fsm.FSMState, dstState fsm.FSMState) error { ?? ?// 從params中解析order參數(shù) ?? ?key, ok := params["order"] ?? ?if !ok { ?? ??? ?return fmt.Errorf("params[\"order\"]不存在。") ?? ?} ?? ?curOrder := key.(*database.Order) ?? ?fmt.Printf("order.ID: %v, order.State: %v\n", curOrder.ID, curOrder.State) ?? ?// 訂單狀態(tài)轉(zhuǎn)移 ?? ?if err := database.UpdateOrderState(curOrder, int(srcState), int(dstState)); err != nil { ?? ??? ?return err ?? ?} ?? ?return nil } // Init 狀態(tài)機(jī)的狀態(tài)轉(zhuǎn)移圖初始化 func Init() { ?? ?orderFSM = fsm.CreateNewFSM(orderTransitionFunc) ?? ?orderFSM.SetTransitionMap(StateOrderInit, EventOrderPlace, StateOrderToBePaid, PlaceAction{}) ? ? ? ? ? ? ? ? ?// 初始化+下單 -> 待支付 ?? ?orderFSM.SetTransitionMap(StateOrderToBePaid, EventOrderPay, StateOrderToBeDelivered, PayAction{}) ? ? ? ? ? ? // 待支付+支付 -> 待發(fā)貨 ?? ?orderFSM.SetTransitionMap(StateOrderToBePaid, EventOrderPayTimeout, StateOrderCancel, nil) ? ? ? ? ? ? ? ? ? ? // 待支付+支付超時(shí) -> 訂單取消 ?? ?orderFSM.SetTransitionMap(StateOrderToBeDelivered, EventOrderDeliver, StateOrderToBeReceived, DeliverAction{}) // 待發(fā)貨+發(fā)貨 -> 待收貨 ?? ?orderFSM.SetTransitionMap(StateOrderToBeReceived, EventOrderReceive, StateOrderDone, ReceiveAction{}) ? ? ? ? ?// 待收貨+收貨 -> 訂單完成 } // ExecOrderTask 執(zhí)行訂單任務(wù),推動狀態(tài)轉(zhuǎn)移 func ExecOrderTask(params map[string]interface{}) error { ?? ?// 從params中解析order參數(shù) ?? ?key, ok := params["order"] ?? ?if !ok { ?? ??? ?return fmt.Errorf("params[\"order\"]不存在。") ?? ?} ?? ?curOrder := key.(*database.Order) ?? ?// 初始化+下單 -> 待支付 ?? ?if curOrder.State == int(StateOrderInit) { ?? ??? ?if err := orderFSM.Push(nil, params, StateOrderInit, EventOrderPlace); err != nil { ?? ??? ??? ?return err ?? ??? ?} ?? ?} ?? ?// 待支付+支付 -> 待發(fā)貨 ?? ?if curOrder.State == int(StateOrderToBePaid) { ?? ??? ?if err := orderFSM.Push(nil, params, StateOrderToBePaid, EventOrderPay); err != nil { ?? ??? ??? ?return err ?? ??? ?} ?? ?} ?? ?// 待支付+支付超時(shí) -> 訂單取消 ?? ?if curOrder.State == int(StateOrderToBePaid) { ?? ??? ?if err := orderFSM.Push(nil, params, StateOrderToBePaid, EventOrderPayTimeout); err != nil { ?? ??? ??? ?return err ?? ??? ?} ?? ?} ?? ?// 待發(fā)貨+發(fā)貨 -> 待收貨 ?? ?if curOrder.State == int(StateOrderToBeDelivered) { ?? ??? ?if err := orderFSM.Push(nil, params, StateOrderToBeDelivered, EventOrderDeliver); err != nil { ?? ??? ??? ?return err ?? ??? ?} ?? ?} ?? ?// 待收貨+收貨 -> 訂單完成 ?? ?if curOrder.State == int(StateOrderToBeReceived) { ?? ??? ?if err := orderFSM.Push(nil, params, StateOrderToBeReceived, EventOrderReceive); err != nil { ?? ??? ??? ?return err ?? ??? ?} ?? ?} ?? ?return nil }
order包中做的事情主要有:
- 定義訂單狀態(tài)機(jī)的狀態(tài)和事件;
- 創(chuàng)建一個(gè)狀態(tài)機(jī),并設(shè)置狀態(tài)轉(zhuǎn)移函數(shù)和狀態(tài)轉(zhuǎn)移圖;
- 執(zhí)行訂單任務(wù),推動狀態(tài)轉(zhuǎn)移。
(2) order_action_place
package order import ( ?? ?"fmt" ?? ?"zuzhiang/database" ) type PlaceAction struct { } // Before 事務(wù)前執(zhí)行,業(yè)務(wù)上允許多次操作 func (receiver PlaceAction) Before(bizParams map[string]interface{}) error { ?? ?fmt.Println("執(zhí)行下單的Before方法。") ?? ?return nil } // Execute 事務(wù)中執(zhí)行,與狀態(tài)轉(zhuǎn)移在同一事務(wù)中 func (receiver PlaceAction) Execute(bizParams map[string]interface{}, tx *database.DB) error { ?? ?fmt.Println("執(zhí)行下單的Execute方法。") ?? ?return nil } // After 事務(wù)后執(zhí)行,業(yè)務(wù)上允許執(zhí)行失敗或未執(zhí)行 func (receiver PlaceAction) After(bizParams map[string]interface{}) error { ?? ?fmt.Println("執(zhí)行下單的After方法。") ?? ?return nil }
(2) ~ (5)是訂單不同動作的聲明和實(shí)現(xiàn)。
(3) order_action_pay
package order import ( ?? ?"fmt" ?? ?"zuzhiang/database" ) type PayAction struct { } // Before 事務(wù)前執(zhí)行,業(yè)務(wù)上允許多次操作 func (receiver PayAction) Before(bizParams map[string]interface{}) error { ?? ?fmt.Println("執(zhí)行支付的Before方法。") ?? ?return nil } // Execute 事務(wù)中執(zhí)行,與狀態(tài)轉(zhuǎn)移在同一事務(wù)中 func (receiver PayAction) Execute(bizParams map[string]interface{}, tx *database.DB) error { ?? ?fmt.Println("執(zhí)行支付的Execute方法。") ?? ?return nil } // After 事務(wù)后執(zhí)行,業(yè)務(wù)上允許執(zhí)行失敗或未執(zhí)行 func (receiver PayAction) After(bizParams map[string]interface{}) error { ?? ?fmt.Println("執(zhí)行支付的After方法。") ?? ?return nil }
(4) order_action_deliver
package order import ( ?? ?"fmt" ?? ?"zuzhiang/database" ) type DeliverAction struct { } // Before 事務(wù)前執(zhí)行,業(yè)務(wù)上允許多次操作 func (receiver DeliverAction) Before(bizParams map[string]interface{}) error { ?? ?fmt.Println("執(zhí)行發(fā)貨的Before方法。") ?? ?return nil } // Execute 事務(wù)中執(zhí)行,與狀態(tài)轉(zhuǎn)移在同一事務(wù)中 func (receiver DeliverAction) Execute(bizParams map[string]interface{}, tx *database.DB) error { ?? ?fmt.Println("執(zhí)行發(fā)貨的Execute方法。") ?? ?return nil } // After 事務(wù)后執(zhí)行,業(yè)務(wù)上允許執(zhí)行失敗或未執(zhí)行 func (receiver DeliverAction) After(bizParams map[string]interface{}) error { ?? ?fmt.Println("執(zhí)行發(fā)貨的After方法。") ?? ?return nil }
(5) order_action_receive
package order import ( ?? ?"fmt" ?? ?"zuzhiang/database" ) type ReceiveAction struct { } // Before 事務(wù)前執(zhí)行,業(yè)務(wù)上允許多次操作 func (receiver ReceiveAction) Before(bizParams map[string]interface{}) error { ?? ?fmt.Println("執(zhí)行收貨的Before方法。") ?? ?return nil } // Execute 事務(wù)中執(zhí)行,與狀態(tài)轉(zhuǎn)移在同一事務(wù)中 func (receiver ReceiveAction) Execute(bizParams map[string]interface{}, tx *database.DB) error { ?? ?fmt.Println("執(zhí)行收貨的Execute方法。") ?? ?return nil } // After 事務(wù)后執(zhí)行,業(yè)務(wù)上允許執(zhí)行失敗或未執(zhí)行 func (receiver ReceiveAction) After(bizParams map[string]interface{}) error { ?? ?fmt.Println("執(zhí)行收貨的After方法。") ?? ?return nil }
4. main包
package main import ( ?? ?"fmt" ?? ?"zuzhiang/database" ?? ?"zuzhiang/order" ) func main() { ?? ?order.Init() ?? ?orderList, dbErr := database.ListAllOrder() ?? ?if dbErr != nil { ?? ??? ?return ?? ?} ?? ?for _, curOrder := range orderList { ?? ??? ?params := make(map[string]interface{}) ?? ??? ?params["order"] = curOrder ?? ??? ?if err := order.ExecOrderTask(params); err != nil { ?? ??? ??? ?fmt.Printf("執(zhí)行訂單任務(wù)出錯(cuò):%v\n", err) ?? ??? ?} ?? ??? ?fmt.Println("\n\n") ?? ?} }
最后在main包里先初始化一個(gè)訂單狀態(tài)機(jī),查詢所有訂單,并使用狀態(tài)機(jī)執(zhí)行訂單任務(wù),推動訂單狀態(tài)轉(zhuǎn)移。注意多個(gè)訂單可以用同一個(gè)狀態(tài)機(jī)來進(jìn)行狀態(tài)的遷移。
三、個(gè)人總結(jié)
為什么要使用狀態(tài)機(jī),我想主要是它可以對一個(gè)復(fù)雜的業(yè)務(wù)流程進(jìn)行模塊化拆分,使得代碼更為易讀。并且擴(kuò)展性更好,如果后續(xù)有新狀態(tài)加入,只需要在原來的基礎(chǔ)上進(jìn)行擴(kuò)展即可,甚至不需要了解整個(gè)業(yè)務(wù)流程。
其次,它將數(shù)據(jù)庫實(shí)體的狀態(tài)流轉(zhuǎn)進(jìn)行了模范化,避免了不同的開發(fā)人員在寫更新數(shù)據(jù)庫實(shí)體狀態(tài)代碼時(shí)可能導(dǎo)致的問題。
到此這篇關(guān)于Go語言狀態(tài)機(jī)的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Go語言狀態(tài)機(jī)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang gorm 計(jì)算字段和獲取sum()值的實(shí)現(xiàn)
這篇文章主要介紹了golang gorm 計(jì)算字段和獲取sum()值的實(shí)現(xiàn)操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12Go語言strconv包實(shí)現(xiàn)字符串和數(shù)值類型的相互轉(zhuǎn)換
這篇文章主要介紹了Go語言strconv包實(shí)現(xiàn)字符串和數(shù)值類型的相互轉(zhuǎn)換,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03用Go+WebSocket快速實(shí)現(xiàn)一個(gè)chat服務(wù)
這篇文章主要介紹了用Go+WebSocket快速實(shí)現(xiàn)一個(gè)chat服務(wù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04Golang實(shí)現(xiàn)smtp郵件發(fā)送的示例代碼
這篇文章主要為大家詳細(xì)介紹了Golang實(shí)現(xiàn)smtp郵件發(fā)送的相關(guān)知識,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03Golang中函數(shù)(Function)和方法(Method)的區(qū)別詳解
在Golang中,大家必然會頻繁使用到函數(shù)(Function)和方法(Method),但是有的同學(xué)可能并沒有注意過函數(shù)和方法的異同點(diǎn),函數(shù)和方法都是用來執(zhí)行特定任務(wù)的代碼塊,雖然很相似,但也有很大的區(qū)別,所以本文將詳細(xì)講解函數(shù)和方法的定義以及它們的異同點(diǎn)2023-07-07