有限状态机

​​英语​​​:finite-state machine

​​​缩写​​

FSM
)又称
有限状态自动机
,简称
状态机
,是表示有限个
​​状态​​
以及在这些状态之间的转移和动作等行为的
​​数学模型​​


就像上面说的,既然是数学模型当然有很多的实现方法。其实最简单容易想到的方法就是使用switch case的写法:



[cpp]
​​ view plain​​
​​ copy​​



1. swtich(case)
2. {
3. case
4. do
5. break;
6. case
7. do
8. break;
9. .......
10. }


[cpp]
​​ view plain​​
​​ copy​​



1. 但是这种写法会带来很多的问题,首先是当状态多的时候,switch case的语句会写的很长,使得可读性非常差。其次,可维护性也很差,每当要添加一个状态转换时,就要在Switch case添加相应的状态转换函数。会使得代码变得冗长,难以扩展。


[cpp]
​​ view plain​​
​​ copy​​



1. 当使用状态模式写状态机的时候,每一个状态就是一个类,添加状态只需要添加一个状态类就行了。在每一个类中实现相应的状态转换函数。


[cpp]
​​ view plain​​
​​ copy​​



1. 使用状态模式的好处:


[cpp]
​​ view plain​​
​​ copy​​



1. 1 每一个状态就是一个类,便于扩展,可读性高


[cpp]
​​ view plain​​
​​ copy​​



1. 2 每一个类有一个状态转换函数,使得整个代码的层次结构,很清晰


[cpp]
​​ view plain​​
​​ copy​​



1. 当然,没有一个东西是完美的。使用状态模式实现的时候,会使得类可能会变得很庞大。当总的来说,还是好处大于坏处的。毕竟代码不仅是出产品,还要考虑这个代码的扩展性还有可读性。一个只实现了功能,但扩展性很差,或者是除了你没有人看得懂,或者是很难看懂的代码,绝不是好代码。简单高效才是我们程序员追求的目标。


[cpp]
​​ view plain​​
​​ copy​​



1. 一个很简单的例子,仿照电梯的例子:


[cpp]
​​ view plain​​
​​ copy​​



1. <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: 状态机,负责状态的装换************************************************************************/#include "statemachine.h"#include "StateDefine.h"using namespace std;StateMachine::StateMachine()
{


//起始的状态为停止状态m_currentState = m_lastState = STOP_STATE;
}

StateMachine::~StateMachine()
{


}

/*** @brief 状态机的初始化函数,负责把每一个状态的类放入Map中进行管理*/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 状态装换函数,当需要切换状态的时候,只需要调用此函数* @param stateId :每一个状态都有一个相应的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 获得上次的状态* @return 返回状态ID*/int StateMachine::getLastState()
{


return m_lastState;
}

/*** @brief 获得当前的状态* @return 返回状态ID*/int StateMachine::getState()
{


return m_currentState;
}
然后是每一个状态的类:
/************************************************************************Des: 下落的状态/************************************************************************/#include "downstate.h"#include "StateDefine.h"#include "statemachine.h"using namespace std;DownState::DownState()
{


}

DownState::~DownState()
{


cout<<"destructor downstate"<<endl;
}

/*** @brief 处理相应的状态装换* @param 传入状态机* @return*/bool DownState::handle(StateMachine* p_machine)
{


//判断上次的状态是否能正确切换到现在的状态if( (p_machine->getLastState() != CLOSE_STATE) || (p_machine->getLastState() != STOP_STATE)){if(p_machine->getLastState() != CLOSE_STATE)cout<<"the lift must be close!"<<endl;elsecout<<"the lift must be stoped"<<endl;return false;}cout<<"the lift is downing "<<endl;return true;
}

/************************************************************************Des:关闭的状态/************************************************************************/#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: 开启的状态/************************************************************************/#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: 停止的状态/************************************************************************/#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: 上升的状态/************************************************************************/#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;
}
下面是公共的头文件,定义了每一个状态对应的枚举值,方便管理
/************************************************************************* Des: 定义一个枚举,每一个状态对于一个值/************************************************************************/#ifndef STATEDEFINE_H#define STATEDEFINE_Henum{CLOSE_STATE,OPEN_STATE,UP_STATE,DOWN_STATE,STOP_STATE,
};

#endif // STATEDEFINE_H
下面是每一个状态的父类,使用了虚函数,使得对外的切换状态的接口是统一的

/************************************************************************* Des: 每一个状态的父类,定义了虚函数(handle),每一个状态都实现了这个函数,* 实现状态的切换具体实现,多态的体现/************************************************************************/#ifndef STATE_H#define STATE_Hclass StateMachine;class State
{


public:State();virtual ~State();virtual bool handle(StateMachine* p_machine) = 0;
};

#endif // STATE_H 使用次状态模式的具体类:
/************************************************************************* Des: 电梯的具体类,负责实现电梯的具体逻辑/************************************************************************/#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);}}
}
使用状态模式确实使得使用避免过度的使用了IF ELSE 或者是Switch case,也使得整个的逻辑变得清晰可见。初探状态模式,还有些不足,以后改进!!(_~ ~_)



[cpp]
​​ view plain​​
​​ copy​​



1. <pre style="margin-top: 0px; margin-bottom: 0px;">