状态机我们大家都知道,有一个专门的设计模式状态机模式,类图大概如下图:不过如果按照下面图来实现的状态机,基本来说非常难用,没有实用性,只能作为教科书的产品。今天我们要实现的是一种通用状态机,可以Send事件,每一个状态可以响应自己注册的事件,同时也可以通过自身或者事件来改变状态机的状态
代码地址:https://github.com/9435202/StateAPI
首先Contex类:
CreateState() 接口,用于创建状态机和父状态机关系
Update() 接口,外部驱动状态机函数
SendEvent() 同步发送事件到当前状态,能发送任意数据到状态中处理
SendAsyncEvent() 异步发送事件到当前状态,能发送任意数据到状态中处理
State类
virtual void start(){} // 状态开始处理 子类实现
virtual void update(){} // update处理 子类实现
virtual void stop(){} // 状态结束处理 子类实现
void set_event_func(); // 设置事件处理回调函数,子类绑定
具体实现如下:
Context.h
#ifndef _CONTEXT_H_
#define _CONTEXT_H_
#include "Event.h"
#include
#include
#include
namespace HsmState
{
class State;
struct NodeState
{
NodeState& operator = (const NodeState& n)
{
_state = n._state;
_father_name = n._father_name;
return *this;
}
State* _state;
std::string _father_name;
};
class Context
{
public:
friend class State;
Context();
~Context();
// 开始状态机
bool Start(std::string name);
// 创建一个状态
// [in] state 状态对象,在Context销毁时,内部释放state
// [in] name 状态名称,为空名称为typedname的值
// [in] father_name 父状态的名称
// [out] 返回state
State* CreateState(State* state, std::string name, std::string father_name = "");
// 更新当前状态
void Update();
// 同步事件
// 发送一个事件,提供给root状态和当前状态处理
// 如果当前状态是子状态,则还会给父状态处理
void SendEvent(EventData event_data);
// 异步事件
void SendAsyncEvent(EventData event_data);
// 获取当前状态名称
std::string GetCurStateName();
private:
// 状态切换
void TransForState(std::string name);
// 递归send
void RecursiveSend(NodeState& node_state, EventData& event_data);
std::unordered_map _states; // 状态列表
NodeState _cur_node_state; // 当前状态名
std::string _cur_name;
std::string _root_name; // 根状态名
};
}
#endif // !STATE_H_
contex.cpp
#include "Context.h"
#include "State.h"
namespace HsmState
{
Context::Context()
{
}
Context::~Context()
{
for (auto iter : _states)
{
if (iter.second._state)
{
delete iter.second._state;
iter.second._state = nullptr;
}
}
_states.clear();
}
// 开始状态机
bool Context::Start(std::string name)
{
std::unordered_map::iterator iter_map = _states.find(name);
if (iter_map != _states.end())
{
_cur_node_state = iter_map->second;
_cur_name = iter_map->first;
iter_map->second._state->start();
}
return false;
}
// 创建一个状态
// [in] state 状态对象,在Context销毁时,内部释放state
// [in] name 状态名称,为空名称为typedname的值
// [in] father_name 父状态的名称
// [out] 返回state
State* Context::CreateState(State* state, std::string name, std::string father_name)
{
NodeState node_state;
node_state._state = state;
node_state._state->SetContext(this);
node_state._father_name = father_name;
_states[name] = node_state;
return state;
}
// 更新当前状态
void Context::Update()
{
_cur_node_state._state->update();
}
// 同步事件
// 发送一个事件,提供给root状态和当前状态处理
// 如果当前状态是子状态,则还会给父状态处理
void Context::SendEvent(EventData event_data)
{
RecursiveSend(_cur_node_state, event_data);
}
// 异步事件
void Context::SendAsyncEvent(EventData event_data)
{
// todo 待实现
}
std::string Context::GetCurStateName()
{
return _cur_name;
}
// 递归send
void Context::RecursiveSend(NodeState& node_state, EventData& event_data)
{
EventDeal event_deal = node_state._state->RunEventFunc(event_data);
if (event_deal == keep_on
&& !node_state._father_name.empty())
{
std::unordered_map::iterator iter_map = _states.find(node_state._father_name);
if (iter_map != _states.end())
{
RecursiveSend(iter_map->second, event_data);
}
}
}
void Context::TransForState(std::string name)
{
std::string str_name = std::string(name);
std::unordered_map::iterator iter_map = _states.find(str_name);
if (iter_map != _states.end())
{
// 停止上一个状态
_cur_node_state._state->stop();
// 初始化下一个状态
_cur_node_state = iter_map->second;
_cur_name = iter_map->first;
_cur_node_state._state->start();
}
}
}
state.h
#ifndef _STATE_H_
#define _STATE_H_
#include "Event.h"
#include
#include
namespace HsmState
{
class Context;
class State
{
public:
// 进入状态时调用,子类重写
virtual void start(){}
// 更新状态,可以由外部周期性调用
virtual void update(){}
// 停止状态是调用,子类重写
virtual void stop(){}
// 设置事件响应回调函数
void set_event_func(std::function func);
EventDeal RunEventFunc(EventData& event_data);
void SetContext(Context* context);
// 切换状态
// [in] name 状态名称
void TransState(std::string name);
private:
std::function _event_func;
Context *_context;
};
}
#endif // !STATE_H_
state.cpp
#include "Context.h"
#include "State.h"
namespace HsmState
{
// 设置时间响应回调函数
void State::set_event_func(std::function func)
{
_event_func = func;
}
EventDeal State::RunEventFunc(EventData& event_data)
{
if (_event_func == nullptr)
return keep_on;
return _event_func(event_data);
}
void State::SetContext(Context* context)
{
_context = context;
}
void State::TransState(std::string name)
{
_context->TransForState(name);
}
}
Event.h
#pragma once
namespace HsmState
{
enum EventDeal
{
tail = 0, // 事件结束处理
keep_on // 事件继续传递
};
// 事件数据
class EventData
{
public:
EventData(int event_type)
{
_event_type = event_type;
_data = nullptr;
}
template
void SetData(T* t)
{
_data = t;
}
template
T* GetData()
{
return (T*)_data;
}
int _event_type;
private:
void* _data;
};
}
二、测试
我使用了一个一天生活状态机来测试
状态变化如下:
测试代码如下:
#include "Context.h"
#include "State.h"
#include
#include
#include
#include
using namespace HsmState;
bool run = true;
enum EventS
{
belazy = 0, // 偷懒事件
};
// 开始状态
class StartState : public State
{
public :
void start()
{
std::cout << "StartState start" << std::endl;
}
void stop()
{
std::cout << "StartState stop" << std::endl;
}
void update()
{
time++;
if (time == 10)
{
TransState("HungerState");
}
}
int time = 0;
};
// 饥饿状态
class HungerState : public State
{
public:
void start()
{
std::cout << "HungerState start" << std::endl;
}
void stop()
{
std::cout << "HungerState stop" << std::endl;
}
void update()
{
time++;
if (time == 10)
{
TransState("Dinner");
}
}
int time = 0;
};
class Dinner : public State
{
public:
void start()
{
std::cout << "Dinner start" << std::endl;
}
void stop()
{
std::cout << "Dinner stop" << std::endl;
}
void update()
{
TransState("DoTheCookingState");
}
};
// 做饭状态
class DoTheCookingState : public State
{
public:
void start()
{
std::cout << "DoTheCookingState start" << std::endl;
}
void stop()
{
std::cout << "DoTheCookingState stop" << std::endl;
}
void update()
{
time++;
if (time == 60)
{
TransState("EatState");
}
}
int time = 0;
};
// 吃饭状态
class EatState : public State
{
public:
void start()
{
std::cout << "EatState start" << std::endl;
}
void stop()
{
std::cout << "EatState stop" << std::endl;
}
void update()
{
time++;
if (time == 5)
{
TransState("SleepState");
}
}
int time = 0;
};
// 饭后睡觉状态
class SleepState : public State
{
public:
void start()
{
std::cout << "SleepState start" << std::endl;
}
void stop()
{
std::cout << "SleepState stop" << std::endl;
}
void update()
{
time++;
if (time == 30)
{
TransState("WorkState");
}
}
int time = 0;
};
// 工作状态
class WorkState : public State
{
public:
void start()
{
std::cout << "WorkState start" << std::endl;
std::function func = std::bind(&WorkState::DealEvent, this, std::placeholders::_1);;
set_event_func(func);
}
void stop()
{
std::cout << "WorkState stop" << std::endl;
}
EventDeal DealEvent(EventData &event_data)
{
switch ((EventS)event_data._event_type)
{
case belazy:
TransState("LoafOnAJob");
break;
default:
break;
}
return keep_on;
}
void update()
{
time++;
if (time == 180)
{
run = false;
}
}
int time = 0;
};
// 工作摸鱼状态
class LoafOnAJob : public State
{
public:
void start()
{
time = 0;
std::cout << "LoafOnAJob start" << std::endl;
}
void stop()
{
std::cout << "LoafOnAJob stop" << std::endl;
}
void update()
{
time++;
if (time == 10)
{
TransState("WorkState");
}
}
int time = 0;
};
// 对象工厂
class Factory
{
public :
static State* CreateState(Context* context, std::string name, std::string parent_name = "")
{
State* state = nullptr;
if (name == "StartState")
{
state = new StartState();
}
else if (name == "HungerState")
{
state = new HungerState();
}
else if (name == "Dinner")
{
state = new Dinner();
}
else if (name == "DoTheCookingState")
{
state = new DoTheCookingState();
}
else if (name == "EatState")
{
state = new EatState();
}
else if (name == "SleepState")
{
state = new SleepState();
}
else if (name == "WorkState")
{
state = new WorkState();
}
else if (name == "LoafOnAJob")
{
state = new LoafOnAJob();
}
context->CreateState(state, name, parent_name);
return state;
}
};
int main()
{
Context* context = new Context();
// 创建状态机
Factory::CreateState(context, "StartState");
Factory::CreateState(context, "HungerState");
Factory::CreateState(context, "Dinner");
Factory::CreateState(context, "DoTheCookingState", "Dinner");
Factory::CreateState(context, "EatState", "Dinner");
Factory::CreateState(context, "SleepState");
Factory::CreateState(context, "WorkState");
Factory::CreateState(context, "LoafOnAJob");
// 开始状态机
context->Start("StartState");
int time = 0;
while (run)
{
time++;
std::this_thread::sleep_for(
std::chrono::duration_cast(std::chrono::milliseconds(10)));
context->Update();
// 如果为工作状态,每隔60分钟发出偷懒事件
if (context->GetCurStateName() == "WorkState"
&& time % 60 == 0)
{
EventData e = EventData((int)belazy);
context->SendEvent(e);
}
}
if (context)
{
delete context;
context = nullptr;
}
std::cout << "state close" << std::endl;
return 0;
}
三、运行结果
工作累了就偷偷懒,真是愉快的一天啊!!!