C++有限狀態機實現詳解
前提:因為最近打算學設計模式的狀態模式,但不是很明白有限狀態機和狀態模式之間的關系,索性用C++實現瞭一個簡單案例復習瞭一下FSM,如果有更好的實現方法,歡迎留言
有限狀態機四大要素
- 現態:當前所處狀態
- 次態:當條件滿足後,即將轉移的下一個狀態
- 動作:當滿足某個事件時執行的動作;動作執行完畢後可以轉移到另一個狀態或保持原有狀態
- 條件:轉移狀態所需的條件,當滿足條件時,會觸發一個動作或進行狀態轉移
C++函數指針實現
案例:學生的日常生活。
- 學生的日常生活包含以下幾個狀態:起床、上學、吃午飯、做作業、睡覺;
- 每個狀態之間進行轉移需要執行相應的事件。
我分為以下幾個步驟來實現:
- (1)繪制狀態轉移圖
- (2)創建狀態轉移的FSMItem類
- 枚舉:所有狀態State、所有事件Event;
- 成員變量:現態_curState、事件_event、次態_nextState
- 成員函數:動作函數
- (3)創建有限狀態機FSM類
- 成員變量:狀態轉移表vector<FSMItem*> _fsmTable
- 成員函數:初始化狀態轉移表、狀態轉移、根據事件執行相應動作
- (4)測試FSM
(1)繪制狀態轉移圖
(2)FSMItem類
//FSM狀態項 class FSMItem { friend class FSM; private: //動作函數 static void getUp() { cout << "student is getting up!" << endl; } static void go2School() { cout << "student is going to school!" << endl; } static void haveLunch() { cout << "student is having lunch!" << endl; } static void doHomework() { cout << "student is doing homework!" << endl; } static void sleeping() { cout << "student is sleeping!" << endl; } public: //枚舉所有狀態 enum State { GETUP = 0, GOTOSCHOOL, HAVELUNCH, DOHOMEWORK, SLEEP }; //枚舉所有事件 enum Events { EVENT1 = 0, EVENT2, EVENT3 }; public: //初始化構造函數 FSMItem(State curState, Events event, void(*action)(), State nextState) :_curState(curState), _event(event), _action(action), _nextState(nextState) {} private: State _curState; //現態 Events _event; //條件 void (*_action)(); //動作 State _nextState; //次態 };
(3)FSM類
class FSM { public: //初始化狀態機 FSM(FSMItem::State curState= FSMItem::GETUP):_curState(curState) { initFSMTable(); } //狀態轉移 void transferState(FSMItem::State nextState) { _curState = nextState; } //根據當前狀態和發生的事件,執行相應的動作,並進行狀態轉移 void handleEvent(FSMItem::Events event) { FSMItem::State curState = _curState; //現態 void (*action)() = nullptr;//動作 FSMItem::State nextState; //次態 bool flag = false; for (int i = 0; i < _fsmTable.size(); i++) { if (event == _fsmTable[i]->_event && curState == _fsmTable[i]->_curState) { flag = true; action = _fsmTable[i]->_action; nextState = _fsmTable[i]->_nextState; break; } } //找到對應的狀態項,執行動作,轉移狀態 if (flag) { if (action) { action(); } transferState(nextState); } } private: //根據畫的狀態轉移圖初始化狀態轉移表 void initFSMTable() { _fsmTable.push_back(new FSMItem(FSMItem::GETUP, FSMItem::EVENT1, &FSMItem::getUp, FSMItem::GOTOSCHOOL)); _fsmTable.push_back(new FSMItem(FSMItem::GOTOSCHOOL, FSMItem::EVENT2, &FSMItem::go2School, FSMItem::HAVELUNCH)); _fsmTable.push_back(new FSMItem(FSMItem::HAVELUNCH, FSMItem::EVENT3, &FSMItem::haveLunch, FSMItem::DOHOMEWORK)); _fsmTable.push_back(new FSMItem(FSMItem::DOHOMEWORK, FSMItem::EVENT1, &FSMItem::doHomework, FSMItem::SLEEP)); _fsmTable.push_back(new FSMItem(FSMItem::SLEEP, FSMItem::EVENT2, &FSMItem::sleeping, FSMItem::GETUP)); } public: FSMItem::State _curState; //現態 private: vector<FSMItem*> _fsmTable; //狀態轉移表 };
(4)測試FSM
#include<iostream> #include<vector> using namespace std; //測試事件變換 void testEvent(FSMItem::Events& event) { switch (event) { case FSMItem::EVENT1: event = FSMItem::EVENT2; break; case FSMItem::EVENT2: event = FSMItem::EVENT3; break; case FSMItem::EVENT3: event = FSMItem::EVENT1; break; } } int main() { FSM *fsm = new FSM(); auto event = FSMItem::EVENT1; while (1) { cout << "event " << event << " is coming..." << endl; fsm->handleEvent(event); cout << "fsm current state is " << fsm->_curState << endl; testEvent(event); } return 0; }
執行效果:
總結
本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!
推薦閱讀:
- 一篇文章帶你瞭解C++(STL基礎、Vector)
- C++數據結構繼承的概念與菱形繼承及虛擬繼承和組合
- C++淺析STL 迭代器 容器的使用
- C++使用文件實現學生信息管理系統
- c++ 虛函數,虛表相關總結