C++状态机框架实现

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/q943520218/article/details/102576873

      状态机我们大家都知道,有一个专门的设计模式状态机模式,类图大概如下图:不过如果按照下面图来实现的状态机,基本来说非常难用,没有实用性,只能作为教科书的产品。今天我们要实现的是一种通用状态机,可以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 <string>
#include <unordered_map>
#include <thread>

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<std::string, NodeState> _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<std::string, NodeState>::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<std::string, NodeState>::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<std::string, NodeState>::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<functional>
#include<string>

namespace HsmState
{
	class Context;

	class State
	{
	public:

		// 进入状态时调用,子类重写
		virtual void start(){}

		// 更新状态,可以由外部周期性调用
		virtual void update(){}

		// 停止状态是调用,子类重写
		virtual void stop(){}

		// 设置事件响应回调函数
		void set_event_func(std::function<EventDeal(EventData&)> func);

		EventDeal RunEventFunc(EventData& event_data); 

		void SetContext(Context* context);

		// 切换状态
		// [in] name 状态名称
		void TransState(std::string name);

	private:
		std::function<EventDeal(EventData&)> _event_func;
		Context *_context;
	};
}
#endif // !STATE_H_



state.cpp

#include "Context.h"
#include "State.h"

namespace HsmState
{
	// 设置时间响应回调函数
	void State::set_event_func(std::function<EventDeal(EventData&)> 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 <class T>
		void SetData(T* t)
		{
			_data = t;
		}

		template <class T>
		T* GetData()
		{
			return (T*)_data;
		}


		int _event_type;
	private:
		void* _data;
	};
}

二、测试

    我使用了一个一天生活状态机来测试

    状态变化如下:

    

测试代码如下:

#include "Context.h"
#include "State.h"
#include <thread>
#include <chrono>
#include <iostream>
#include <functional>

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<EventDeal(EventData&)> 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>(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;
}

三、运行结果

工作累了就偷偷懒,真是愉快的一天啊!!!

猜你喜欢

转载自blog.csdn.net/q943520218/article/details/102576873