C++有限狀態(tài)機(jī)實(shí)現(xiàn)詳解
前提:因?yàn)樽罱蛩銓W(xué)設(shè)計(jì)模式的狀態(tài)模式,但不是很明白有限狀態(tài)機(jī)和狀態(tài)模式之間的關(guān)系,索性用C++實(shí)現(xiàn)了一個(gè)簡(jiǎn)單案例復(fù)習(xí)了一下FSM,如果有更好的實(shí)現(xiàn)方法,歡迎留言
有限狀態(tài)機(jī)四大要素
- 現(xiàn)態(tài):當(dāng)前所處狀態(tài)
- 次態(tài):當(dāng)條件滿足后,即將轉(zhuǎn)移的下一個(gè)狀態(tài)
- 動(dòng)作:當(dāng)滿足某個(gè)事件時(shí)執(zhí)行的動(dòng)作;動(dòng)作執(zhí)行完畢后可以轉(zhuǎn)移到另一個(gè)狀態(tài)或保持原有狀態(tài)
- 條件:轉(zhuǎn)移狀態(tài)所需的條件,當(dāng)滿足條件時(shí),會(huì)觸發(fā)一個(gè)動(dòng)作或進(jìn)行狀態(tài)轉(zhuǎn)移
C++函數(shù)指針實(shí)現(xiàn)
案例:學(xué)生的日常生活。
- 學(xué)生的日常生活包含以下幾個(gè)狀態(tài):起床、上學(xué)、吃午飯、做作業(yè)、睡覺(jué);
- 每個(gè)狀態(tài)之間進(jìn)行轉(zhuǎn)移需要執(zhí)行相應(yīng)的事件。
我分為以下幾個(gè)步驟來(lái)實(shí)現(xiàn):
- (1)繪制狀態(tài)轉(zhuǎn)移圖
- (2)創(chuàng)建狀態(tài)轉(zhuǎn)移的FSMItem類
- 枚舉:所有狀態(tài)State、所有事件Event;
- 成員變量:現(xiàn)態(tài)_curState、事件_event、次態(tài)_nextState
- 成員函數(shù):動(dòng)作函數(shù)
- (3)創(chuàng)建有限狀態(tài)機(jī)FSM類
- 成員變量:狀態(tài)轉(zhuǎn)移表vector<FSMItem*> _fsmTable
- 成員函數(shù):初始化狀態(tài)轉(zhuǎn)移表、狀態(tài)轉(zhuǎn)移、根據(jù)事件執(zhí)行相應(yīng)動(dòng)作
- (4)測(cè)試FSM
(1)繪制狀態(tài)轉(zhuǎn)移圖
(2)FSMItem類
//FSM狀態(tài)項(xiàng) class FSMItem { friend class FSM; private: //動(dòng)作函數(shù) 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: //枚舉所有狀態(tài) enum State { GETUP = 0, GOTOSCHOOL, HAVELUNCH, DOHOMEWORK, SLEEP }; //枚舉所有事件 enum Events { EVENT1 = 0, EVENT2, EVENT3 }; public: //初始化構(gòu)造函數(shù) FSMItem(State curState, Events event, void(*action)(), State nextState) :_curState(curState), _event(event), _action(action), _nextState(nextState) {} private: State _curState; //現(xiàn)態(tài) Events _event; //條件 void (*_action)(); //動(dòng)作 State _nextState; //次態(tài) };
(3)FSM類
class FSM { public: //初始化狀態(tài)機(jī) FSM(FSMItem::State curState= FSMItem::GETUP):_curState(curState) { initFSMTable(); } //狀態(tài)轉(zhuǎn)移 void transferState(FSMItem::State nextState) { _curState = nextState; } //根據(jù)當(dāng)前狀態(tài)和發(fā)生的事件,執(zhí)行相應(yīng)的動(dòng)作,并進(jìn)行狀態(tài)轉(zhuǎn)移 void handleEvent(FSMItem::Events event) { FSMItem::State curState = _curState; //現(xiàn)態(tài) void (*action)() = nullptr;//動(dòng)作 FSMItem::State nextState; //次態(tài) 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; } } //找到對(duì)應(yīng)的狀態(tài)項(xiàng),執(zhí)行動(dòng)作,轉(zhuǎn)移狀態(tài) if (flag) { if (action) { action(); } transferState(nextState); } } private: //根據(jù)畫(huà)的狀態(tài)轉(zhuǎn)移圖初始化狀態(tài)轉(zhuǎn)移表 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; //現(xiàn)態(tài) private: vector<FSMItem*> _fsmTable; //狀態(tài)轉(zhuǎn)移表 };
(4)測(cè)試FSM
#include<iostream> #include<vector> using namespace std; //測(cè)試事件變換 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; }
執(zhí)行效果:
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
C++11中的時(shí)間庫(kù)std::chrono(引發(fā)關(guān)于時(shí)間的思考)
這篇文章主要介紹了C++11中的時(shí)間庫(kù)std::chrono(引發(fā)關(guān)于時(shí)間的思考),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04c字符串,string對(duì)象,字符串字面值的區(qū)別詳解
以下是對(duì)c字符串,string對(duì)象,字符串字面值的區(qū)別進(jìn)行了詳細(xì)的介紹,需要朋友可以 過(guò)來(lái)參考下2013-09-09基于C語(yǔ)言實(shí)現(xiàn)計(jì)算生辰八字五行的示例詳解
生辰八字,簡(jiǎn)稱八字,是指一個(gè)人出生時(shí)的干支歷日期;年月日時(shí)共四柱干支,每柱兩字,合共八個(gè)字。這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)計(jì)算生辰八字五行的示例代碼,需要的可以參考一下2023-03-03Linux線程同步之信號(hào)C語(yǔ)言實(shí)例
這篇文章主要介紹了Linux線程同步之信號(hào)C語(yǔ)言實(shí)例,本文直接給出代碼實(shí)例,需要的朋友可以參考下2015-04-04