這個系列最終實現(xiàn)的狀態(tài)機并不是一個標準的狀態(tài)機,把狀態(tài)機的很多標準的概念進行了簡化寞钥,對概念的東西做了減法,實現(xiàn)了具備基本功能的狀態(tài)機(很多所謂狀態(tài)機更高級的功能理郑,如:偽態(tài)蹄溉,也可以在基本功能實現(xiàn))您炉。整個狀態(tài)機的實現(xiàn)將分為下面幾個章節(jié)介紹
- 狀態(tài)機介紹
- 簡單有限狀態(tài)機的實現(xiàn)
- 簡單有限狀態(tài)機的應(yīng)用實例
- 簡單狀態(tài)機功能增強
- 有限狀態(tài)機狀態(tài)持久化設(shè)計
- 有限狀態(tài)機持久化實現(xiàn)
當前章節(jié)以理論為主
有限狀態(tài)機概念
有限狀態(tài)機簡稱就是狀態(tài)機柒爵,因為一般的狀態(tài)機的狀態(tài)都是離散和可舉的,即為有限赚爵,所以后面的介紹都不加有限二字棉胀。狀態(tài)機表示有限個狀態(tài)以及在這些狀態(tài)之間的轉(zhuǎn)移和動作等行為的數(shù)學模型法瑟。通俗的描述狀態(tài)機就是定義了一套狀態(tài)変更的流程:狀態(tài)機包含一個狀態(tài)集合,定義當狀態(tài)機處于某一個狀態(tài)的時候它所能接收的事件以及可執(zhí)行的行為霎挟,執(zhí)行完成后,狀態(tài)機所處的狀態(tài)氓扛。所以狀態(tài)機會包含以下幾個重要的元素:
- State:狀態(tài)论笔。一個標準的狀態(tài)機最少包含兩個狀態(tài):初始和終態(tài)。初態(tài)是狀態(tài)機初始化后所處的狀態(tài)最楷,而終態(tài)顧名思義就是狀態(tài)機結(jié)束時所處的狀態(tài)。其他的狀態(tài)都是一些流轉(zhuǎn)中停留的狀態(tài)。標準的狀態(tài)機還會涉及到一些中間態(tài)犯建,存在中間態(tài)的狀態(tài)機流程就會比較復(fù)雜(用處也不是特別大讲冠,而且可以通過其他方式實現(xiàn)),所以在目標實現(xiàn)的狀態(tài)機里不會引入這個概念适瓦。
- Event:事件竿开。還有中描述叫Trigger,表達的意思都一樣玻熙,就是要執(zhí)行某個操作的觸發(fā)器或口令:當狀態(tài)機處于某個狀態(tài)時否彩,只有外界告訴狀態(tài)機要干什么事情的時候,狀態(tài)機才會去執(zhí)行具體的行為嗦随,來完成外界想要它完成的操作列荔。比如出去吃飯,說“點菜”枚尼,服務(wù)員才會拿著小本過來記錄你要吃的菜肌毅,說的那句“點菜”,就相當于Event姑原。
- Action:行為悬而。狀態(tài)變更索要執(zhí)行的具體行為。還是拿上面點菜的例子锭汛,服務(wù)員拿小本記錄你定的菜的過程就是Action
- Transition:變更笨奠。一個狀態(tài)接收一個事件執(zhí)行了某些行為到達了另外一個狀態(tài)的過程就是一個Transition袭蝗。定義Transition就是在定義狀態(tài)機的運轉(zhuǎn)流程。
上圖就是一個最簡單的狀態(tài)機般婆,一個初態(tài)到腥,一個流轉(zhuǎn)狀態(tài),一個終態(tài)蔚袍,初態(tài)到流狀態(tài)是不需要任何操作的乡范,State1當發(fā)生了Event1事件時,執(zhí)行Action1到達了終態(tài)啤咽。(我們最終實現(xiàn)的狀態(tài)機晋辆,會把初態(tài)和終態(tài)都當做一個流狀態(tài)來對待)。
說了這么多宇整,狀態(tài)機能干什么瓶佳?狀態(tài)機主要的應(yīng)用場景就是流程控制。一個狀態(tài)機定義以后鳞青,在某個狀態(tài)下就只接收固定的Event霸饲,也就是執(zhí)行指定的操作,這樣流程就能按照預(yù)期定義的那樣流轉(zhuǎn)臂拓,不會出現(xiàn)亂入的情況厚脉,執(zhí)行了一些在某狀態(tài)下不允許執(zhí)行的操作。一個很典型的應(yīng)用就是工作流引擎:以工作流中典型的審批流程為例胶惰,審批流程按照預(yù)先定義的流程流轉(zhuǎn)的固定的某些人手里傻工,只有這一批固定的人才能審批,當審批后(可能是一個人審批童番,也可能是多個人審批)才會流轉(zhuǎn)到下個節(jié)點精钮,由下個節(jié)點的審批人繼續(xù)審批威鹿,一直流轉(zhuǎn)到最后一個節(jié)點剃斧。狀態(tài)機的流轉(zhuǎn)可以人工干預(yù),也可以自動流轉(zhuǎn)忽你。定義為自動流轉(zhuǎn)后幼东,把業(yè)務(wù)流程定義完成后,只要添加一個定時任務(wù)科雳,整個流程的運轉(zhuǎn)就都由狀態(tài)機來完成了根蟹。此外,當狀態(tài)機加入了持久化操作后糟秘,所有的狀態(tài)流轉(zhuǎn)都會落地简逮,當業(yè)務(wù)出現(xiàn)異常,方便定位問題尿赚,當流程定義的足夠細粒度的話散庶,還可以通過驅(qū)動狀態(tài)機來實現(xiàn)重入蕉堰,恢復(fù)異常的節(jié)點。
狀態(tài)模式
在實現(xiàn)狀態(tài)機之前悲龟,我們順便簡單的看一下設(shè)計模式中的狀態(tài)模式屋讶,這個模式跟我們實現(xiàn)狀態(tài)機的代碼結(jié)構(gòu)還是有一定的關(guān)系的。
狀態(tài)模式:封裝基于狀態(tài)的行為须教,并將行為委托到當前的狀態(tài)皿渗。
試想一下,現(xiàn)在有一種業(yè)務(wù)場景存在多個狀態(tài)轻腺,比如一個要遭受攻擊的游戲人物乐疆,當人物遭受攻擊后我們要減少人物的血量,而當前人物可能處于的狀態(tài)有如下(游戲中常見的一些場景):剛復(fù)活(對一切攻擊免疫)约计,正常狀態(tài)诀拭,物理攻擊免疫,魔法攻擊免疫煤蚌,攻擊隨機無效耕挨,各種疊加態(tài)。當攻擊來了尉桩,人物該怎么掉血筒占。在非使用狀態(tài)模式的情況下,一種常見的寫法蜘犁,人物接受攻擊翰苫,然后開始各種判斷現(xiàn)在人物所處于的狀態(tài),各種if...else这橙,當新的需求來額時候奏窑,就修改這些if...else。而采用狀態(tài)模式屈扎,行為委托類保存著當前人物所處的狀態(tài)埃唯,當攻擊來了,委托類會把該攻擊交由持有的狀態(tài)來處理鹰晨,實現(xiàn)了對修改關(guān)閉墨叛,對擴展開放。類圖如下(具體就不上代碼了模蜡,感興趣的可以自己研究一下):
- Context:可以理解為上下文漠趁,它持有當前的狀態(tài),同時對外暴露狀態(tài)行為接口
- State:定義了狀態(tài)下的行為接口
- ConcreteState:行為接口的具體實現(xiàn)
其中Context是一個關(guān)鍵忍疾,在我們將要實現(xiàn)的狀態(tài)機里扮演者重要的角色闯传。
此外我們將要的實現(xiàn)的狀態(tài)機遠遠不是一個狀態(tài)模式的一個實現(xiàn),要比它復(fù)雜的多卤妒。
目標狀態(tài)機功能介紹
- 狀態(tài)機的定義:通過定義State甥绿,Event叠必,Action,Transition來實現(xiàn)狀態(tài)機的流轉(zhuǎn)妹窖,摒棄標準狀態(tài)機中那些較復(fù)雜的概念(通過其他方式來實現(xiàn)所謂的較復(fù)雜的操作)
- 狀態(tài)持久化:數(shù)據(jù)持久化到數(shù)據(jù)庫纬朝,實現(xiàn)狀態(tài)機的中斷重啟
- 上下文保存與傳遞:提供一套流程流轉(zhuǎn)過程中參數(shù)的傳遞機制
- 并發(fā)控制:提供不同狀態(tài)機隔離,同一狀態(tài)機單實例運行機制
- 功能增強:接口或注解的形式實現(xiàn)自觸發(fā)骄呼,重試共苛,定時執(zhí)行
github上有一開源狀態(tài)機,算是github上狀態(tài)機系列java得星最多的項目蜓萄,功能已經(jīng)做的很強大隅茎,本人早期的時候關(guān)注過,但是到目前為止已經(jīng)做的很復(fù)雜了嫉沽,超出了大部分常規(guī)的使用場景辟犀,而且?guī)讉€版本下來,代碼風格也有了很大的變化绸硕。感興趣的同學可以先看一下:
https://github.com/hekailiang/squirrel
此外Spring也有一套狀態(tài)機堂竟,但對spring版本有要求,有生產(chǎn)需求的同學也可以考慮一下