一个简单的有限状态机,
三种状态:
- 停止状态
- 运行状态
- 暂停状态
三个事件
- Start
- Pause
- Stop
状态转换说明:
- Stopped状态:通过Start事件转换为Running状态
- Running状态:通过Pause事件可转换为Pause状态
- Pause状态:通过Start事件可转换为Running状态
实现方式有多种
使用if-else或switch-case
使用if-else或switch-case判断并设置状态之间的转换,比较小儿科,如果写不好会有很多很多的bug,最后当状态变得很多很复杂的时候,bug可能不好找完,尤其是在加入新的状态以后.
有一个明显的优点:就是想怎么改就怎么改,容易上手
有一个明显的缺点:很难扩展新的状态,增加新的事件
不做过多的解释哈。
基于boost的state_machine来实现,如下:
state_machine.h
#pragma once
#include <iostream>
#include <boost/statechart/event.hpp>
#include <boost/statechart/result.hpp>
#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/custom_reaction.hpp>
//Pre-declarations
class StoppedState;
class RunningState;
class PauseState;
//Three events declaration
class StopEvent : public boost::statechart::event<StopEvent>
{
public:
StopEvent()
{
std::cout << "StopEvent" << std::endl;
}
virtual ~StopEvent() = default;
};
class StartEvent : public boost::statechart::event<StartEvent>
{
public:
StartEvent()
{
std::cout << "StartEvent" << std::endl;
}
virtual ~StartEvent() = default;
};
class PauseEvent : public boost::statechart::event<PauseEvent>
{
public:
PauseEvent()
{
std::cout << "PauseEvent" << std::endl;
}
virtual ~PauseEvent() = default;
};
//enum state declaration
enum class State : std::int8_t
{
Stopped = 83, //S, S for Stopped status
Running = 82, //R, R for Running status
Pause = 80 //P, P for Pause status
};
//StateMachine main class
class StateMachine : public boost::statechart::state_machine<StateMachine, StoppedState> //the initialized status is Stopped
{
public:
StateMachine() = default;
virtual ~StateMachine() = default;
State state_; //should not set it to public, but for simple, so so
};
//Three states
class StoppedState : public boost::statechart::simple_state<StoppedState, StateMachine>
{
public:
typedef boost::statechart::custom_reaction<StartEvent> reactions;
boost::statechart::result react(const StartEvent & event) // StartEvent, will set the status from Stopped to Running
{
context<StateMachine>().state_ = State::Running;
std::cout << "CurrentState = " << static_cast<std::underlying_type<State>::type>(context<StateMachine>().state_) << std::endl << std::endl;
return transit<RunningState>();
}
virtual ~StoppedState() = default;
};
class RunningState : public boost::statechart::simple_state<RunningState, StateMachine>
{
public:
typedef boost::statechart::custom_reaction<PauseEvent> reactions;
boost::statechart::result react(const PauseEvent & event)// PauseEvent, will set the status from Running to Paused
{
context<StateMachine>().state_ = State::Pause;
std::cout << "CurrentState = " << static_cast<std::underlying_type<State>::type>(context<StateMachine>().state_) << std::endl << std::endl;
return transit<PauseState>();
}
virtual ~RunningState() = default;
};
class PauseState : public boost::statechart::simple_state<PauseState, StateMachine>
{
public:
typedef boost::statechart::custom_reaction<StartEvent> reactions;
boost::statechart::result react(const StartEvent & event) // StartEvent, will set the status from Paused to Running
{
context<StateMachine>().state_ = State::Running;
std::cout << "CurrentState = " << static_cast<std::underlying_type<State>::type>(context<StateMachine>().state_) << std::endl << std::endl;
return transit<RunningState>();
}
virtual ~PauseState() = default;
};
state_machine.cc
#include "state_machine.h"
//It is an empty file, all code is in its header file
main.cc
#include <iostream>
#include "state_machine.h"
int main(int argc, char * argv[])
{
StateMachine sm;
sm.initiate();
//exception testing
sm.process_event(PauseEvent()); //can't pause
sm.process_event(StartEvent());
sm.process_event(PauseEvent());
sm.process_event(StartEvent());
sm.process_event(PauseEvent());
sm.process_event(StopEvent()); //can't stop
sm.process_event(StartEvent());
sm.process_event(StopEvent()); //can't stop
sm.process_event(StopEvent()); //can't stop
return 0;
}
It is easy to use.