C/C++用狀態轉移表聯合函式指標陣列實現狀態機FSM
狀態機在工程中使用非常的頻繁,有如下常見的三種實現方法:
1. switch-case
實現,適合簡單的狀態機;
2. 二維狀態表state-event
實現,邏輯清晰,但是矩陣通常比較稀疏,而且維護麻煩;
3. 用狀態轉移表stateTransfer Table
實現,陣列大小等於狀體轉移邊個數,易擴充套件;
下面用一個例子來進行詳細說明,描述的如下場景:
描述物件:門
狀態:開著、關著、鎖著 (這裡的關著指關了但未鎖的狀態)
事件:開門、關門、上鎖、解鎖
程式碼實現用列舉來定義狀態和事件,操作資料節點轉移到目的狀態用函式實現。列舉本身預設是從0開始的int
核心資料結構如下:
狀態:列舉型別
事件:列舉型別
狀態轉移結構體:{當前狀態、事件、下個狀態},定義一個全域性陣列來使用
狀態變更函式:到下個狀態(放到陣列中與狀態列舉對應起來)
此種實現方法容易擴充套件,增加狀態和事件都比較容易。如果存在一個狀態通過對應事件可以轉移到多個狀態的情形,則可以擴充套件狀態轉移函式,或者在狀態轉移結構中增加一個判斷函式欄位。
程式碼實現如下:
#include <iostream>
using namespace std;
typedef enum{
OPENED,
CLOSED,
LOCKED,
} State;
typedef enum{
OPEN,
CLOSE,
LOCK,
UNLOCK
} Event;
typedef struct{
State currentState;
Event event;
State NextState;
} StateTransfer;
typedef struct{
State state;
int transferTimes;
}Door;
StateTransfer g_stateTransferTable[]{
{OPENED, CLOSE, CLOSED},
{CLOSED, OPEN, OPENED},
{CLOSED, LOCK, LOCKED},
{LOCKED, UNLOCK, CLOSED},
};
void toOpen(Door& door);
void toClose(Door& door);
void toLock(Door& door);
typedef void (*pfToState)(Door& door);
pfToState g_pFun[] = {toOpen, toClose, toLock}; //狀態列舉值對應下標
void toOpen(Door& door){
door.state = OPENED;
cout << "open the door!\n";
}
void toClose(Door& door){
door.state = CLOSED;
cout << "close the door!\n";
}
void toLock(Door& door){
door.state = LOCKED;
cout << "lock the door!\n";
}
void transfer(Door& door,const Event event){
for (int i = 0; i < sizeof(g_stateTransferTable)/sizeof(StateTransfer); ++i) {
if(door.state == g_stateTransferTable[i].currentState &&
event == g_stateTransferTable[i].event){
g_pFun[g_stateTransferTable[i].NextState](door);
door.transferTimes++;
cout << "transfer ok!\n";
return;
}
}
cout << "This event cannot transfer current state!!\n";
return;
}
void printDoor(const Door& door){
string stateNote[] = {"opened","closed","locked"}; // 下標正好對應狀態列舉值
cout << "the door's state is: " << stateNote[door.state] << endl;
cout << "the door transfer times is: " << door.transferTimes << endl;
}
int main(){
Door door = {CLOSED, 0};
printDoor(door);
transfer(door, OPEN);
printDoor(door);
transfer(door, LOCK);
printDoor(door);
transfer(door, CLOSE);
printDoor(door);
return 0;
}
執行結果如下:
the door’s state is: closed
the door transfer times is: 0
open the door!
transfer ok!
the door’s state is: opened
the door transfer times is: 1
This event cannot transfer current state!!
the door’s state is: opened
the door transfer times is: 1
close the door!
transfer ok!
the door’s state is: closed
the door transfer times is: 2