整理:狀態機的兩種寫法對比
狀態機可以用兩種方法實現:豎著寫(在狀態中判斷事件)和橫著寫(在事件中判斷狀態)。這兩種實現在本質上是完全等效的,但在實際操作中,效果卻截然不同。
==================================
豎著寫(在狀態中判斷事件) C程式碼片段
==================================
cur_state = nxt_state;
switch(cur_state)
{ //在當前狀態中判斷事件
case s0: //在s0狀態
if(e0_event)
{ //如果發生e0事件,那麼就執行a0動作,並保持狀態不變;
執行a0動作;
//nxt_state = s0; //因為狀態號是自身,所以可以刪除此句,以提高執行速度。
}
else if(e1_event)
{ //如果發生e1事件,那麼就執行a1動作,並將狀態轉移到s1態;
執行a1動作;
nxt_state = s1;
}
else if(e2_event)
{ //
執行a2動作;
nxt_state = s2;
}
break;
case s1: //在s1狀態
if(e2_event)
{ //如果發生e2事件,那麼就執行a2動作,並將狀態轉移到s2態;
執行a2動作;
nxt_state = s2;
}
break;
case s2: //
if(e0_event)
{ //如果發生e0事件,那麼就執行a0動作,並將狀態轉移到s0態;
執行a0動作;
nxt_state = s0;
}
}
==================================
橫著寫(在事件中判斷狀態) C程式碼片段
==================================
//e0事件發生時,執行的函式
void e0_event_function(int * nxt_state)
{
int cur_state;
cur_state = *nxt_state;
switch(cur_state)
{
case s0:
case s2:
執行a0動作;
*nxt_state = s0;
}
}
//e1事件發生時,執行的函式
void e1_event_function(int * nxt_state)
{
int cur_state;
cur_state = *nxt_state;
switch(cur_state)
{
case s0:
執行a1動作;
*nxt_state = s1;
}
}
//e2事件發生時,執行的函式
void e2_event_function(int * nxt_state)
{
int cur_state;
cur_state = *nxt_state;
switch(cur_state)
{
case s0:
case s1:
執行a2動作;
*nxt_state = s2;
}
}
上面橫豎兩種寫法的程式碼片段,實現的功能完全相同,但是,橫著寫的效果明顯好於豎著寫的效果。理由如下:
1、豎著寫隱含了優先順序排序(其實各個事件是同優先順序的),排在前面的事件判斷將毫無疑問地優先於排在後面的事件判斷。這種if/else if寫法上的限制將破壞事件間原有的關係。而橫著寫不存在此問題。
2、由於處在每個狀態時的事件數目不一致,而且事件發生的時間是隨機的,無法預先確定,導致豎著寫淪落為順序查詢方式,結構上的缺陷使得大量時間被浪費。對於橫著寫,在某個時間點,狀態是唯一確定的,在事件裡查詢狀態只要使用switch語句,就能一步定位到相應的狀態,延遲時間可以預先準確估算。而且在事件發生時,呼叫事件函式,在函式裡查詢唯一確定的狀態,並根據其執行動作和狀態轉移的思路清晰簡潔,效率高,富有美感。
總之,我個人認為,在軟體裡寫狀態機,使用橫著寫的方法比較妥帖。
豎著寫的方法也不是完全不能使用,在一些小專案裡,邏輯不太複雜,功能精簡,同時為了節約記憶體耗費,豎著寫的方法也不失為一種合適的選擇。