有限状态机(使用状态模式C++实现)
生活随笔
收集整理的這篇文章主要介紹了
有限状态机(使用状态模式C++实现)
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
最近在研究怪物的AI,由于怪物的AI是使用有限狀態(tài)機(jī)來實(shí)現(xiàn)的。所以就查看關(guān)于有限狀態(tài)機(jī)的東西。根據(jù)這幾天的查看資料,知道了有限狀態(tài)機(jī)是計(jì)算機(jī)科學(xué)中一個(gè)很重要的概念。而且有限狀態(tài)機(jī)是一個(gè)抽象的概念,具體實(shí)現(xiàn)是多種多樣的。根據(jù)維基百科的介紹,它是這樣的一個(gè)概念:
有限狀態(tài)機(jī)
(
英語:finite-state machine
,
縮寫
:
FSM
)又稱
有限狀態(tài)自動(dòng)機(jī)
,簡(jiǎn)稱
狀態(tài)機(jī)
,是表示有限個(gè)
狀態(tài)
以及在這些狀態(tài)之間的轉(zhuǎn)移和動(dòng)作等行為的
數(shù)學(xué)模型
。
swtich(case)?? {?? case?STATE1:?? ????????do?something;?? ????????break;?? case?STATE2:?? ????????do?something;?? ????????break;?? .......?? }??
[cpp] view plain copy 但是這種寫法會(huì)帶來很多的問題,首先是當(dāng)狀態(tài)多的時(shí)候,switch?case的語句會(huì)寫的很長(zhǎng),使得可讀性非常差。其次,可維護(hù)性也很差,每當(dāng)要添加一個(gè)狀態(tài)轉(zhuǎn)換時(shí),就要在Switch?case添加相應(yīng)的狀態(tài)轉(zhuǎn)換函數(shù)。會(huì)使得代碼變得冗長(zhǎng),難以擴(kuò)展。??
[cpp] view plain copy 當(dāng)使用狀態(tài)模式寫狀態(tài)機(jī)的時(shí)候,每一個(gè)狀態(tài)就是一個(gè)類,添加狀態(tài)只需要添加一個(gè)狀態(tài)類就行了。在每一個(gè)類中實(shí)現(xiàn)相應(yīng)的狀態(tài)轉(zhuǎn)換函數(shù)。??
[cpp] view plain copy 使用狀態(tài)模式的好處:??
[cpp] view plain copy 1?每一個(gè)狀態(tài)就是一個(gè)類,便于擴(kuò)展,可讀性高??
[cpp] view plain copy 2?每一個(gè)類有一個(gè)狀態(tài)轉(zhuǎn)換函數(shù),使得整個(gè)代碼的層次結(jié)構(gòu),很清晰??
[cpp] view plain copy 當(dāng)然,沒有一個(gè)東西是完美的。使用狀態(tài)模式實(shí)現(xiàn)的時(shí)候,會(huì)使得類可能會(huì)變得很龐大。當(dāng)總的來說,還是好處大于壞處的。畢竟代碼不僅是出產(chǎn)品,還要考慮這個(gè)代碼的擴(kuò)展性還有可讀性。一個(gè)只實(shí)現(xiàn)了功能,但擴(kuò)展性很差,或者是除了你沒有人看得懂,或者是很難看懂的代碼,絕不是好代碼。簡(jiǎn)單高效才是我們程序員追求的目標(biāo)。??
[cpp] view plain copy 一個(gè)很簡(jiǎn)單的例子,仿照電梯的例子:??
[cpp] view plain copy <pre?style="color:?rgb(37,?37,?37);?margin-top:?0px;?margin-bottom:?0px;"><pre?style="margin-top:?0px;?margin-bottom:?0px;"><span?style="?color:#008000;">/************************************************************************</span>??
Des: 狀態(tài)機(jī),負(fù)責(zé)狀態(tài)的裝換
************************************************************************/
#include "statemachine.h"
#include "StateDefine.h"
using namespace std;
StateMachine::StateMachine()
{
//起始的狀態(tài)為停止?fàn)顟B(tài)
m_currentState = m_lastState = STOP_STATE;
}
StateMachine::~StateMachine()
{
}
/**
* @brief 狀態(tài)機(jī)的初始化函數(shù),負(fù)責(zé)把每一個(gè)狀態(tài)的類放入Map中進(jìn)行管理
*/
void StateMachine::init()
{
m_stateManager[0] = new CloseState();
m_stateManager[1] = new OpenState();
m_stateManager[2] = new UpState();
m_stateManager[3] = new DownState();
m_stateManager[4] = new StopState();
(m_stateManager[4])->handle(this);
}
/**
* @brief 狀態(tài)裝換函數(shù),當(dāng)需要切換狀態(tài)的時(shí)候,只需要調(diào)用此函數(shù)
* @param stateId :每一個(gè)狀態(tài)都有一個(gè)相應(yīng)的ID,定義在StateDefine的頭文件中
*/
void StateMachine::changeState(int stateId)
{
if( stateId == m_currentState )
{
cout<<"curent state is "<<stateId<<"doesn't transfrom state"<<endl;
return;
}
else
{
int temp = m_lastState;
m_lastState = m_currentState;
m_currentState = stateId;
std::map<int,State*>::iterator it = m_stateManager.find(stateId);
if( it != m_stateManager.end() )
{
if( !(it->second)->handle(this))
{
m_currentState = m_lastState;
m_lastState = temp;
}
}
}
}
/**
* @brief 獲得上次的狀態(tài)
* @return 返回狀態(tài)ID
*/
int StateMachine::getLastState()
{
return m_lastState;
}
/**
* @brief 獲得當(dāng)前的狀態(tài)
* @return 返回狀態(tài)ID
*/
int StateMachine::getState()
{
return m_currentState;
} 然后是每一個(gè)狀態(tài)的類:
/************************************************************************
Des: 下落的狀態(tài)
/************************************************************************/
#include "downstate.h"
#include "StateDefine.h"
#include "statemachine.h"
using namespace std;
DownState::DownState()
{
}
DownState::~DownState()
{
cout<<"destructor downstate"<<endl;
}
/**
* @brief 處理相應(yīng)的狀態(tài)裝換
* @param 傳入狀態(tài)機(jī)
* @return
*/
bool DownState::handle(StateMachine* p_machine)
{
//判斷上次的狀態(tài)是否能正確切換到現(xiàn)在的狀態(tài)
if( (p_machine->getLastState() != CLOSE_STATE) || (p_machine->getLastState() != STOP_STATE))
{
if(p_machine->getLastState() != CLOSE_STATE)
cout<<"the lift must be close!"<<endl;
else
cout<<"the lift must be stoped"<<endl;
return false;
}
cout<<"the lift is downing "<<endl;
return true;
}
/************************************************************************
Des:關(guān)閉的狀態(tài)
/************************************************************************/
#include "closestate.h"
#include "StateDefine.h"
#include "statemachine.h"
using namespace std;
CloseState::CloseState()
{
}
CloseState::~CloseState()
{
cout<<"destructor closestate"<<endl;
}
bool CloseState::handle(StateMachine* p_machine)
{
if( (p_machine->getLastState() != OPEN_STATE))
{
cout<<"the lift must be closed!"<<endl;
return false;
}
cout<<"the lift is closing "<<endl;
return true;
}
/************************************************************************
* Des: 開啟的狀態(tài)
/************************************************************************/
#include "openstate.h"
#include "StateDefine.h"
#include "statemachine.h"
using namespace std;
OpenState::OpenState()
{
}
OpenState::~OpenState()
{
}
bool OpenState::handle(StateMachine* p_machine)
{
if( p_machine->getLastState() != STOP_STATE )
{
cout<<"the lift must be stop!"<<endl;
return false;
}
cout<<"the lift is opening"<<endl;
return true;
}
/************************************************************************
* Des: 停止的狀態(tài)
/************************************************************************/
#include "stopstate.h"
#include "statemachine.h"
#include "StateDefine.h"
using namespace std;
StopState::StopState()
{
}
StopState::~StopState()
{
}
bool StopState::handle(StateMachine* p_machine)
{
if(p_machine->getLastState() == p_machine->getState())
{
cout<<"the lift is stop "<<endl;
return true;
}
if( p_machine->getLastState() == STOP_STATE )
{
cout<<"the lift have already be stopping!"<<endl;
return false;
}
cout<<"the lift is stop "<<endl;
return true;
}
/************************************************************************
* Des: 上升的狀態(tài)
/************************************************************************/
#include "upstate.h"
#include "StateDefine.h"
#include "statemachine.h"
using namespace std;
UpState::UpState()
{
}
UpState::~UpState()
{
cout<<"destrucotor update"<<endl;
}
bool UpState::handle(StateMachine* p_machine)
{
if( p_machine->getLastState() != CLOSE_STATE )
{
cout<<"the lift must be close!"<<endl;
return false;
}
cout<<"the lift is uping"<<endl;
return true;
} 下面是公共的頭文件,定義了每一個(gè)狀態(tài)對(duì)應(yīng)的枚舉值,方便管理
/************************************************************************
* Des: 定義一個(gè)枚舉,每一個(gè)狀態(tài)對(duì)于一個(gè)值
/************************************************************************/
#ifndef STATEDEFINE_H
#define STATEDEFINE_H
enum{
CLOSE_STATE,
OPEN_STATE,
UP_STATE,
DOWN_STATE,
STOP_STATE,
};
#endif // STATEDEFINE_H
下面是每一個(gè)狀態(tài)的父類,使用了虛函數(shù),使得對(duì)外的切換狀態(tài)的接口是統(tǒng)一的
/************************************************************************
* Des: 每一個(gè)狀態(tài)的父類,定義了虛函數(shù)(handle),每一個(gè)狀態(tài)都實(shí)現(xiàn)了這個(gè)函數(shù),
* 實(shí)現(xiàn)狀態(tài)的切換具體實(shí)現(xiàn),多態(tài)的體現(xiàn)
/************************************************************************/
#ifndef STATE_H
#define STATE_H
class StateMachine;
class State
{
public:
State();
virtual ~State();
virtual bool handle(StateMachine* p_machine) = 0;
};
#endif // STATE_H 使用次狀態(tài)模式的具體類:
/************************************************************************
* Des: 電梯的具體類,負(fù)責(zé)實(shí)現(xiàn)電梯的具體邏輯
/************************************************************************/
#include "lift.h"
#include <iostream>
#include "StateDefine.h"
using namespace std;
Lift::Lift()
{
}
Lift::~Lift()
{
delete this->m_stateMachine;
this->m_stateMachine = nullptr;
}
/**
* @brief 電梯的初始化,使用按鍵模擬電梯的行為
*/
void Lift::init()
{
this->m_stateMachine = new StateMachine();
this->m_stateMachine->init();
while (true) {
cout<<"enter the value"<<endl;
char str[8] = {0};
cin>>str;
if( !strcmp(str,"c"))
{
this->m_stateMachine->changeState(CLOSE_STATE);
}
else if( !strcmp(str,"o"))
{
this->m_stateMachine->changeState(OPEN_STATE);
}
else if( !strcmp(str,"u"))
{
this->m_stateMachine->changeState(UP_STATE);
}
else if( !strcmp(str,"d"))
{
this->m_stateMachine->changeState(DOWN_STATE);
}
else if( !strcmp(str,"s"))
{
this->m_stateMachine->changeState(STOP_STATE);
}
}
} 使用狀態(tài)模式確實(shí)使得使用避免過度的使用了IF ELSE 或者是Switch case,也使得整個(gè)的邏輯變得清晰可見。初探狀態(tài)模式,還有些不足,以后改進(jìn)!!(_~ ~_)
[cpp] view plain copy<pre?style="margin-top:?0px;?margin-bottom:?0px;">??
? 就像上面說的,既然是數(shù)學(xué)模型當(dāng)然有很多的實(shí)現(xiàn)方法。其實(shí)最簡(jiǎn)單容易想到的方法就是使用switch case的寫法:
[cpp] view plain copy
[cpp] view plain copy
總結(jié)
以上是生活随笔為你收集整理的有限状态机(使用状态模式C++实现)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在C/C++语言中使用正则表达式
- 下一篇: 状态机之C++解析