泥球型狀態機

2021-12-30 03:35:42 字數 4188 閱讀 6135

泥球型狀態機:對於電商類的系統、遊戲和公司內部流程系統來說,最複雜的莫過於處理其中的狀態扭轉。

如我公司的訂單購買系統:

預約=>審核=>打款=>上傳憑條=>憑條審核=>打款核驗=>返傭對賬=>返傭憑條審核=>返傭

這期間,每乙個狀態有包括了,「通過」 / 「拒絕」的操作。

通常來說,面對這樣的需求,最容易想到的解決方案就是,定義不同的列舉值,不同狀態之間的扭轉就使用if-else或者switch-case來做判斷。如下面所示,根據前端傳遞過來的不同操作值 orderop來做狀態操作判斷,進行不同的狀態處理。

switch (orderop) 對於短期來說,這個邏輯並沒有什麼不對,但是,隨著需求不斷的增加,操作許可權的安全校驗分離,它的跳轉就會變的不可維護。然後,我們的系統狀態扭轉,就像似乙個泥球,如下圖所示:

我們分析一下上面的**邏輯缺陷:

1.多餘的orderop操作

將所有的狀態扭轉操作向前端暴露,如果能夠猜對狀態的列舉值,理論上是可以從任意狀態跳轉到任意狀態。

過多的狀態判斷過多的狀態,會不斷的增加switch-case和if-else判斷,**上難以閱讀,後期開發風險過大。

無法控制許可權其實對於每乙個狀態的操作流程來說,並不是都具有跳轉到下乙個狀態的許可權的。比如,只有先購買才能付款、先付款才能發貨等等。然而,我們在許可權審核的時候,不可能每乙個state都去review。

根據存在的問題,尋找對應的解決方案。

分析每乙個狀態的操作方式所有的操作都只有兩種角色

-操作者

- 修改狀態屬性

- 取消

-審核者

- 通過

- 不通過

其實,這麼一看每乙個狀態的操作還可以列舉出來的,我們稱之為:有限狀態。

定義狀態扭轉狀態的跳轉不再由swich-case來做操作,在乙個固定的地方定義下乙個操作,和與操作匹配的下乙個狀,一目了然。

狀態分層狀態越來越多,我們可以對這麼多狀態進行乙個歸類。如,

-購買前

- 預約狀態

- 預約審核狀態

- 付款

- 已付款

-購買中

- 待發貨

- 待收貨

- 待評價

-購買後

- 售後投訴

- 投訴處理

對於每乙個上層狀態來說,我們不用過多的關心它的子狀態在其中如何扭轉。只需要定義,如只有在「購買前-已付款」狀態才能跳轉到「購買中」。「購買前」狀態中的子狀態如何跳轉到購買前不用思考。

即如下所示:

其實對於整個設計模式來說,這種資料機構有乙個專有的名詞————狀態機。狀態機是ai中常用的一種架構,有很多中實現方式。而且實現簡單,甚至用乙個switch-case就可以了;然而對於多流程結構化的狀態操作是有乙個專有的設計方式:層次化狀態機(hfsm)。

定義狀態分別定義訂單中的每乙個狀態的列舉,並設定歸屬的上層狀態

/*** 訂單狀態列舉

* * @author zhoushengtao

* @since 2016/12/18.

*/public enum orderstateenum

public iorderaction getorderaction()

public int getorderno()

public ordersectionenum getordersectionenum()

}為了方便區分,我們又叫上層為乙個「環節

/***

* 訂單環節列舉

* * @author zhoushengtao

* @since 2016-12-18 16:48:10

*/public enum ordersectionenum

/*** 獲取該環節的入口狀態

* @return 入口狀態值

*/public int getentranceorderno()

}將訂單型別切換制定統一入口/**

* 訂單狀態機操作單例

* * @author zhoushengtao

* @since 2016/12/17.

*/public class orderstatemachine extends observable

/*** 單例

* @param order 訂單

* @return ordersection

*/public static orderstatemachine getinstance(order order)

sordersection.setstate(orderstateenum.getstate(order.getorderno()));

sordersection.mcontext.setorder(order);

sordersection.mcontext.setordersection(sordersection);

assert(sordersection.getstate() != null);

return sordersection;

}/**

* 修改

*/public void modify()

/*** 取消

*/public void cancel()

/*** 審核通過

*/public void auditpass()

/*** 審核失敗

*/public void auditfailure()

/*** 獲取當前狀態

*/private orderstateenum getstate()

/*** 設定新狀態

* @param newstate 新狀態

*/private void setstate(orderstateenum newstate)

/*** 切換新狀態

* @param newstate 新狀態

*/public void transnewstate(orderstateenum newstate)

} else

notifyobservers(newstate);}}

}抽象每乙個列舉的操作/**

* 確認訂單狀態

* * @author zhoushengtao

* @since 2016/12/18.

*/public class orderconfirmaction extends iorderaction

@override

public void cancel(orderstatecontext context)

@override

public void auditpass(orderstatecontext context)

@override

public void auditfailure(orderstatecontext context)

}測試操作public static void main(string args) 此**demo是從專案裡面剝離出來的,沒有什麼實際的邏輯,韜哥我放到github上:

共大家參考學習,寫的不對的地方請多包涵。

要為狀態定義入口 / 出口 要詳細設計每乙個狀態,列出層次化狀態結構,利於分工理解 每乙個子狀態操作邏輯少,不易出錯 狀態列舉定義,將列舉值、操作、跳轉限制合為一體,清晰明了。大規模支援較差 高併發容易出錯(需要加入操作佇列) 沒有書寫狀態切換log(後期排查很重要) 沒有動態化設定邏輯,遊戲設計中往往是讓遊戲策劃可以動態的修改狀態的切換邏輯。

FPGA 狀態機的模型之Moore型狀態機

上篇博文 狀態機,fpga的靈魂,說到了狀態機的基礎知識,講到了狀態機的組成六要素,工作四要素。這篇博文來講狀態機的模型之moore狀態機,從標題也能看出,狀態機的知識並沒有結束,後面還會提到mealy型狀態機。根據狀態機的輸出與其現態 輸入之間的關係,可將fpga中的狀態機抽象為三種基本模型 mo...

FPGA 狀態機的模型之Mealy型狀態機

上篇博文講了 moore型狀態機,這篇博文和上篇博文思路一致,如果讀懂了上篇博文,這篇博文就很容易理解了。如果乙個狀態機的輸出是由現態和輸入共同決定的,那麼它就是乙個mealy型的狀態機。而按照驅動輸出的數位電路特性,又將mealy型狀態機細分為mealy 1型 mealy 2型 mealy 3型,...

狀態機 狀態機0

近半年都忙於做專案,沒有太多的時間去整理和總結在專案中用過的技術 個人還是覺得技術需要總結提煉和沉澱的,忙到沒時間去總結提公升其實不 是什麼好事,這次講下狀態機,在戰鬥型別的遊戲中角色有多種不同的狀態,而狀態的切換錯綜複雜,23種設計模式中有一種模式叫做狀態模式,不過 這種模式是把狀態切換條件放到各...