深入浅出理解有限状态机
有限狀態(tài)機(jī)是一種用來進(jìn)行對象行為建模的工具,其作用主要是描述對象在它的生命周期內(nèi)所經(jīng)歷的狀態(tài)序列,以及如何響應(yīng)來自外界的各種事件。在計算機(jī)科學(xué)中,有限狀態(tài)機(jī)被廣泛用于建模應(yīng)用行為、硬件電路系統(tǒng)設(shè)計、軟件工程,編譯器、網(wǎng)絡(luò)協(xié)議、和計算與語言的研究。比如下圖非常有名的TCP協(xié)議狀態(tài)機(jī)。
其實我們在編程時實現(xiàn)相關(guān)業(yè)務(wù)邏輯時經(jīng)常需要處理各種事件和狀態(tài)切換,寫各種switch/case 和if/else ,所以我們其實可能一直都在跟有限狀態(tài)機(jī)打交道,只是可能沒有意識到。在處理一些業(yè)務(wù)邏輯比較復(fù)雜的需求時,可以先看看是否適合用一個有限狀態(tài)機(jī)來描述,如果可以把業(yè)務(wù)模型抽象成一個有限狀態(tài)機(jī),那么代碼就會邏輯特別清晰,結(jié)構(gòu)特別規(guī)整。
下面我們就來聊聊所謂的狀態(tài)機(jī),以及它如何在代碼中實現(xiàn)。
1、狀態(tài)機(jī)的要素
狀態(tài)機(jī)可歸納為4個要素,即現(xiàn)態(tài)、條件、動作、次態(tài)。“現(xiàn)態(tài)”和“條件”是因,“動作”和“次態(tài)”是果。詳解如下:
①現(xiàn)態(tài):是指當(dāng)前所處的狀態(tài)。
②條件:又稱為“事件”。當(dāng)一個條件被滿足,將會觸發(fā)一個動作,或者執(zhí)行一次狀態(tài)的遷移。
③動作:條件滿足后執(zhí)行的動作。動作執(zhí)行完畢后,可以遷移到新的狀態(tài),也可以仍舊保持原狀態(tài)。動作不是必需的,當(dāng)條件滿足后,也可以不執(zhí)行任何動作,直接遷移到新狀態(tài)。
④次態(tài):條件滿足后要遷往的新狀態(tài)。“次態(tài)”是相對于“現(xiàn)態(tài)”而言的,“次態(tài)”一旦被激活,就轉(zhuǎn)變成新的“現(xiàn)態(tài)”了。
我們可以用狀態(tài)表了表示整個過程,如下圖所示。
狀態(tài)表這里需要注意的兩個問題:
1、避免把某個“程序動作”當(dāng)作是一種“狀態(tài)”來處理。那么如何區(qū)分“動作”和“狀態(tài)”?“動作”是不穩(wěn)定的,即使沒有條件的觸發(fā),“動作”一旦執(zhí)行完畢就結(jié)束了;而“狀態(tài)”是相對穩(wěn)定的,如果沒有外部條件的觸發(fā),一個狀態(tài)會一直持續(xù)下去。
2、狀態(tài)劃分時漏掉一些狀態(tài),導(dǎo)致跳轉(zhuǎn)邏輯不完整。
所以維護(hù)上述一張狀態(tài)表就非常必要,而且有意義了。從表中可以直觀看出那些狀態(tài)直接存在跳轉(zhuǎn)路徑,那些狀態(tài)直接不存在。如果不存在,就把對應(yīng)的單元格置灰。 每次寫代碼之前先把表格填寫好,并且對置灰的部分重點review,看看是否有“漏態(tài)”,然后才是寫代碼。QA拿到這張表格之后,寫測試用例也是手到擒來。
2、狀態(tài)機(jī)在object-C的代碼實現(xiàn)。
我在開發(fā)百度地圖導(dǎo)航過程頁以及百度CarLife的反控手機(jī)識別中都用到了有些狀態(tài)機(jī)編程,下面我結(jié)合個人的經(jīng)驗,給大家分享一個iOS程序中實現(xiàn)有限狀態(tài)機(jī)的寫法。
先回顧一下上面那個狀態(tài)表,其中狀態(tài)變遷時執(zhí)行的動作,可能是由一系列的元動作組成,并且通常都是跟現(xiàn)態(tài)和次態(tài)強(qiáng)相關(guān)的,所以,我把狀態(tài)表做一個改進(jìn),如下所示:
其中:FSM_FUN(stateA,stateB) 就表示,從狀態(tài)stateA跳轉(zhuǎn)到stateB時要執(zhí)行的所有元動作的有序集。
1、準(zhǔn)備工作,狀態(tài)定義和事件定義
宏定義這里沒有啥特殊的,主要是借助宏定義,比較巧妙的實現(xiàn)枚舉值到字符串的轉(zhuǎn)換,比如枚舉值stateA,能自動生成字符串@“stateA”,用于后面的狀態(tài)函數(shù)名拼接。這是一個通用的枚舉值自動轉(zhuǎn)字符串的解決方案,參考的鏈接( http://stackoverflow.com/a/202511)
2、Model類定義
iOS開發(fā)都會采用MVC架構(gòu)或者相關(guān)變種,但是狀態(tài)的維護(hù)都會實現(xiàn)在Model中。這里定義了一個簡單的TestModel,它有一個成員變量state,保存著當(dāng)前的狀態(tài)。
Model定義3、實現(xiàn)Model類的一個category,
里面主要定義和實現(xiàn)了狀態(tài)跳轉(zhuǎn)時要執(zhí)行的一些動作。
4、重新Model的setState方法,使得在設(shè)置狀態(tài)時能自動去執(zhí)行狀態(tài)跳轉(zhuǎn)時需要執(zhí)行的動作。
5、處理事件輸入,實現(xiàn)狀態(tài)跳轉(zhuǎn)邏輯。
這里有兩種寫法,一種是在狀態(tài)中判斷事件:
狀態(tài)中判斷事件一種是事件中判斷狀態(tài):
事件中判斷狀態(tài)思考與討論:
狀態(tài)跳轉(zhuǎn)邏輯的兩種寫法,實現(xiàn)的功能和效果完全相同,孰優(yōu)孰劣,歡迎留言探討。
本人觀點:一般業(yè)務(wù)場景來說,狀態(tài)的數(shù)量是確定的切數(shù)目較少,不同狀態(tài)下需要處理的事件也不一樣。而觸發(fā)的事件數(shù)量則比較多,采用上面第二種方式在事件中判斷狀態(tài)也有利于把里面一層的switch/case剝離出來當(dāng)成單獨的函數(shù),做一些代碼模塊結(jié)構(gòu)的優(yōu)化,故推薦使用第二種方式,事件中判斷狀態(tài)。
優(yōu)化后的狀態(tài)變化函數(shù)代碼,如下圖。
優(yōu)化后歡迎探討
本文主要介紹了一下什么是有限狀態(tài)機(jī),然后通過一個具體的代碼示例介紹了一些本人在狀態(tài)機(jī)編程上的經(jīng)驗和理解,歡迎各位進(jìn)行交流指正。
謝謝大家的寶貴時間。
作者:我是云峰小羅 鏈接:http://www.jianshu.com/p/5eb45c64f3e3 來源:簡書 著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。總結(jié)
以上是生活随笔為你收集整理的深入浅出理解有限状态机的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于有限自动机的一篇不错的文章
- 下一篇: 状态机思路在程序设计中的应用