在上一文中,我们介绍了该状态机模型的使用方法。通过例子,我们发现可以使用该模型快速构建满足基本业务需求的状态机。本文我们将解析该模型的基础代码,以便大家可以根据自己状态机特点进行修改。(转载请指明出于breaksoftware的csdn博客)  该模板库的基础方法实现在之后给出的工程的AutoStateChart.h中,该文件一共215行,其中有16行是辅助调试代码。以上一文中状态机类为例:  public AutoStateChart::  CAutoStateChartMachine<CMachine_Download_Run_App, CStoreofMachine> CMachine_Download_Run_App类继承于模板类CAutoStateChartMachine,该模板类有两个参数:继承类自身和CStoreofMachine。CStoreofMachine类顾名思义,其是状态机中用于存储数据的类。为什么要设计这样的类?因为在我们的状态机模型中,每个基础状态都是割裂的。这样设计的一个好处便是我们可以让每个基础状态的逻辑代码独立,和其他模块没有任何耦合。当我们要删除某个状态时,我们只要将它从状态机的跳转声明中摘除即可。当我们要新增某个状态时,我们也只要在状态机跳转中做相应声明即可。但是往往优点也伴随着缺点:它使得每个基础状态类的数据交互产生了障碍。特别是没有上下文关系的基础状态,跳跃性的传递信息将变得非常困难。于是我们就需要一个存活于整个状态机声明周期的“数据库”,它可以被每个基础状态类访问和修改。于是CStoreofMachine就应运而生。因为该类比较独立,所以我们先从该类开始解析。首先我们看下该类的声明: #pragma once #include "AutoStateChart.h"   #define PROPERTY(type,name)													\ public:																		\ 	void Set##name(const type& n) {										 \ 		m_##name = n;														\ 	}																		\ 	type Get##name() {														\ 		return m_##name;													\ 	}																		\ 	__declspec(property(get = Get##name, put = Set##name)) type Prop##name;	\ private:																	\ 	type m_##name;															\   class CStoreofMachine{ 	PROPERTY(std::string, ValueString); 	PROPERTY(std::wstring, ValueWString);  PROPERTY(int, ValueInt); }  该类的写法可能只适合于windows的vs平台,其他平台没论证过。其实它的内容是非常简单的,就是暴露成员变量的set和get方法。只是我觉得这种写法比较有意思,才在这儿罗列下。  我们再看下该类在模板中的使用,我们先从最基础的类开始解析 class CEmpytLocalStore{}; 	template<class Store = CEmpytLocalStore> 	class CLocalStoreAccess{ 	public: 		typedef boost::function< Store& () > func; 		Store& GetStore(){return m_pFunc();}; 		void SetStore(func& pCallback){m_pFunc = pCallback;}; 	public: 		func m_pFunc; 	};我们先定义了一个空类——CEmptyLocalStore,它相当于一个默认的“数据库”。当模板的使用者不需要“数据库”时,就可以在模板中不声明“数据库”类,此时我们的CEmptyLocalStore就生效了。比如我们上例的状态机可以改成: class CMachine_Download_Run_App : public AutoStateChart::CAutoStateChartMachine<CMachine_Download_Run_App> CLocalStoreAccess类主要提供如下作用: 设置访问“数据库”类对象的方法——SetStore  获取“数据库”类对象——GetStore  成员变量m_pFunc是一个函数指针,用于获取“数据库”类对象。该变量将由CLoaclStoreAccess继承类设置,相当于CLocalStoreAccess暴露了设置访问“数据库”类对象的能力。而它并不保存“数据库”类对象——它只提供“访问”能力,而不提供“存储”能力。 	template<class Store = CEmpytLocalStore> 	class CLocalStoreBase: 		public boost::enable_shared_from_this<CLocalStoreBase<Store>>, 		public CLocalStoreAccess<Store> { 	public: 		void Init(){ func pfunc = boost::bind(&CLocalStoreBase<Store>::_GetStore, shared_from_this()); SetStore(pfunc);}; 	private: 		Store& _GetStore(){return m_Store;}; 	private: 		Store m_Store; 	}; CLoaclStoreBase类的私有成员变量m_Store就是“数据库”类对象,即该类提供了“存储”功能。它继承于CLoaclStoreAccess类,使得该类具备了访问数据库的能力——虽然它的私有方法可以访问“数据库”类对象,但是我还是希望将这些能力分开。因为之后介绍的基础状态类要有“访问”的能力,而不应该具备“存储”的能力。如果不将这些能力进行拆分,将会导致层次结构混乱。 CLoaclStoreBase类的init方法,打通了和ClocalStoreAccess的关系——设置函数指针。 介绍完用于存储上下文的模板类后,我们现在可以关注下状态机相关的类了。我们先看上一文中一个基础状态类的例子 class CSimpleState_Download_From_A :  public AutoStateChart::CAutoStateChartBase<CSimpleState_Download_From_A, CMachine_Download_Run_App, CStoreofMachine>  CSimpleState_Download_From_A类继承于CAutoStateChartBase模板类。第一个模板参数是继承类自身,第二个是它所属的状态机,第三个是“数据库”类。我们在看下CAutoStateChartBase类的声明
  	template<class T, class MachineOrCompositeStates, class Store = CEmpytLocalStore> 	class CAutoStateChartBase: 		public boost::enable_shared_from_this<CAutoStateChartBase<T,MachineOrCompositeStates,Store>>, 		public CLocalStoreAccess<Store> 	{ 		BOOST_TYPEOF_REGISTER_TYPE(T) 	public: 		std::string GetCurrentState(){ return typeid(T).name();}; 		bool IsCompositeStates(){return false;}; 		void SetInitState( const std::string& strState ){};   	public: 		virtual void Entry(){};  		virtual std::string Exit(){return "";}; 	}; 该模板类使用第一个模板参数类的类名作为其继承类的状态,并使用GetCurrentState方法提供获取功能。比如上例中的状态名为class CSimpleState_Download_From_A。这个模板类继承于CLocalStoreAccess模板类,使得继承类具有可以“访问”第三个模板参数类——“数据库”类的能力——不具备“存储”能力。同时该类还暴露了两个方法——Entry和Exit,他们分别用于在进出该状态时,让状态机调用。  状态和存储类都介绍完了,我们就剩下调度状态变化的状态机类和复合状态类。其实从某种程度上说,复合状态是一种简单的状态机,它们在很多地方存在共性。我们从状态机类入口,进行讲解。首先看下上一文中的例子 class CMachine_Download_Run_App :  public AutoStateChart::CAutoStateChartMachine<CMachine_Download_Run_App, CStoreofMachine>   状态机类需要继承于CAutoStateChartMachine模板类,该类声明如下: template<class T, class LocalStore = CEmpytLocalStore> 	class CAutoStateChartMachine: 		public boost::enable_shared_from_this<CAutoStateChartMachine<T,LocalStore>>, 		public CLocalStoreAccess<LocalStore> 	{ 	public: 		typedef LocalStore SelfStore; 		typedef T Self; 	public: 		CAutoStateChartMachine(){m_spStore.reset();}; 		virtual ~CAutoStateChartMachine(){}; 	private: 		virtual bool Transition(){return false;}; 	public: 		void StartMachine() { 			if ( !m_spStore ) { 				m_spStore = boost::make_shared<CLocalStoreBase<LocalStore>>(); 				m_spStore->Init(); 				SetStore( m_spStore->m_pFunc ); 			} 			while( Transition()){}; 		}; 	private: 		void Init(){}; 	public: 		bool IsCompositeStates(){return false;}; 	protected: 		std::string m_strCurrentState; 		std::string m_strCondition; 		MapString m_MapCompositeStatesSubState; 		boost::shared_ptr<CLocalStoreBase<LocalStore>> m_spStore; 	}; 我们先看下这个类的成员变量。m_strCurrentState保存了状态机在跳转中的当前状态,m_strCondition保存了状态机中当前状态之前的状态的输出,它用于决定状态跳转方向。m_MapCompositeStatesSubState用于保存状态机中离开复合状态时的最后状态,即它记录复合状态机的浅历史。m_spStore指向“数据库”类对象。  该模板类最重要的函数就是StartMachine,它在第一次被调用时创建了“数据库”类对象。然后死循环调用Transition方法。Tansition方法是个虚方法,它是整个模型的核心。状态机类需要实现自己的Transition方法,以使得状态机可以运转起来。  我们再看下复合状态类的基础模板 template<class T, class MachineOrCompositeStates, class LocalStore = CEmpytLocalStore> 	class CCompositeStates: 		public CAutoStateChartBase<T,MachineOrCompositeStates,LocalStore>{ 		BOOST_TYPEOF_REGISTER_TYPE(T) 	public: 		CCompositeStates(){}; 		~CCompositeStates(){}; 	private: 		virtual bool Transition(){return false;}; 	public: 		virtual void Entry(){while(Transition());}; 		virtual std::string Exit(){return m_strCondition;}; 	public: 		std::string GetCurrentState(){return m_strCurrentState;}; 		bool IsCompositeStates(){return true;}; 		void SetInitState( const std::string& strState ){ m_strCurrentState = strState; }; 	protected: 		std::string m_strCurrentState; 		std::string m_strCondition; 		MapString m_MapCompositeStatesSubState; 	}; 因为复合状态也是一种状态,所以它也要有Entry和Exit两种方法。而其Entry方法就是调用Transition方法。该模板类的Transition方法也是虚方法,这意味着继承于该模板类的方法也要去实现Transition。  于是所有的重心都集中于Transition方法的实现。  为了让代码美观,我参考了MFC中使用宏简洁代码的思路,设计了如下的宏: #define STARTSTATE(state)														\ 	do {																		\ 		boost::shared_ptr<state> sp = boost::make_shared<state>();				\ 		sp->SetStore( m_pFunc );												\ 		if ( sp->IsCompositeStates() ) {										\ 			std::string strState = typeid(state).name();						\ 			BOOST_AUTO(it, m_MapCompositeStatesSubState.find(strState));		\ 			if ( m_MapCompositeStatesSubState.end() != it ) {					\ 				sp->SetInitState(it->second);									\ 				if ( DEBUGFRAMEFLAG ) {											\ 					std::string strInitState = it->second;						\ 					std::cout<<"CompositeStates SetInitState:"<<strInitState<<std::endl;\ 				}																\ 			}																	\ 		}																		\ 		sp->Entry();															\ 		m_strCondition = sp->Exit();											\ 		if ( sp->IsCompositeStates() ) {										\ 			std::string strState = typeid(state).name();						\ 			std::string strInnerState = sp->GetCurrentState();					\ 			m_MapCompositeStatesSubState[strState] = strInnerState;				\ 			if ( DEBUGFRAMEFLAG ) {												\ 				std::cout<<"CompositeStates SaveState:"<<strState<< " " << strInnerState<< std::endl;	\ 			}																	\ 		}																		\ 	} while (0);																\   #define	REGISTERSTATECONVERTBEGIN(startstate)									\ 	bool Transition() {															\ 		do {																	\ 			if ( m_strCurrentState.empty() ) {									\ 				m_strCurrentState = typeid(startstate).name();					\ 				STARTSTATE(startstate);											\ 				return true;													\ 			}																	\ 		}while(0);																\ #define REGISTERSTATECONVERT(fromstate,condition,tostate)						\ 		do {																	\ 			std::string strFromState = typeid(fromstate).name();				\ 			std::string strToState = typeid(tostate).name();					\ 			if ( DEBUGFRAMEFLAG	) {												\ 				std::cout<<"strFromState:"<<strFromState<<std::endl;				\ 				std::cout<<"condition:"<<condition<<std::endl;						\ 				std::cout<<"strToState:"<<strToState<<std::endl;					\ 				std::cout<<"m_strCurrentState:"<<m_strCurrentState<<std::endl;		\ 				std::cout<<"m_strCondition:"<<m_strCondition<<std::endl<<std::endl;	\ 			}																		\ 			if ( IsCompositeStates() ) {											\ 				if ( strFromState != m_strCurrentState								\ 					|| ( !m_strCondition.empty() && condition != m_strCondition ) ) { \ 						break;														\ 				}																	\ 			}																		\ 			else {																	\ 				if ( strFromState != m_strCurrentState								\ 					|| condition != m_strCondition ) {								\ 					break;															\ 				}																	\ 			}																		\ 			m_strCurrentState = strToState;										\ 			STARTSTATE(tostate);												\ 			return true;														\ 		}while(0);																\ #define REGISTERSTATECONVERTEND()												\ 		return false;															\ 	};	 然后复合状态类和状态机类只要使用这些宏去组织状态跳转,就可以清晰的描述过程了。 最后,如果你想学C/C++可以私信小编“01”获取素材资料以及开发工具和听课权限哦!  |