該模板庫的基礎方法實現在之後給出的工程的AutoStateChart.h中,該文件一共215行,其中有16行是輔助調試代碼。以上一文中狀態機類為例:
class CMachine_Download_Run_App : public AutoStateChart::CAutoStateChartMachineCMachine_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我們先定義了一個空類——CEmptyLocalStore,它相當於一個默認的“數據庫”。當模板的使用者不需要“數據庫”時,就可以在模板中不聲明“數據庫”類,此時我們的CEmptyLocalStore就生效了。比如我們上例的狀態機可以改成:class CLocalStoreAccess{ public: typedef boost::function< Store& () > func; Store& GetStore(){return m_pFunc();}; void SetStore(func& pCallback){m_pFunc = pCallback;}; public: func m_pFunc; };
class CMachine_Download_Run_App : public AutoStateChart::CAutoStateChartMachineCLocalStoreAccess類主要提供如下作用: 設置訪問“數據庫”類對象的方法——SetStore 獲取“數據庫”類對象——GetStore 成員變量m_pFunc是一個函數指針,用於獲取“數據庫”類對象。該變量將由CLoaclStoreAccess繼承類設置,相當於CLocalStoreAccess暴露了設置訪問“數據庫”類對象的能力。而它並不保存“數據庫”類對象——它只提供“訪問”能力,而不提供“存儲”能力。
templateCLoaclStoreBase類的私有成員變量m_Store就是“數據庫”類對象,即該類提供了“存儲”功能。它繼承於CLoaclStoreAccess類,使得該類具備了訪問數據庫的能力——雖然它的私有方法可以訪問“數據庫”類對象,但是我還是希望將這些能力分開。因為之後介紹的基礎狀態類要有“訪問”的能力,而不應該具備“存儲”的能力。如果不將這些能力進行拆分,將會導致層次結構混亂。class CLocalStoreBase: public boost::enable_shared_from_this >, public CLocalStoreAccess { public: void Init(){ func pfunc = boost::bind(&CLocalStoreBase ::_GetStore, shared_from_this()); SetStore(pfunc);}; private: Store& _GetStore(){return m_Store;}; private: Store m_Store; };
class CSimpleState_Download_From_A : public AutoStateChart::CAutoStateChartBaseCSimpleState_Download_From_A類繼承於CAutoStateChartBase模板類。第一個模板參數是繼承類自身,第二個是它所屬的狀態機,第三個是“數據庫”類。我們在看下CAutoStateChartBase類的聲明
template該模板類使用第一個模板參數類的類名作為其繼承類的狀態,並使用GetCurrentState方法提供獲取功能。比如上例中的狀態名為class CSimpleState_Download_From_A。這個模板類繼承於CLocalStoreAccess模板類,使得繼承類具有可以“訪問”第三個模板參數類——“數據庫”類的能力——不具備“存儲”能力。同時該類還暴露了兩個方法——Entry和Exit,他們分別用於在進出該狀態時,讓狀態機調用。class CAutoStateChartBase: public boost::enable_shared_from_this >, public CLocalStoreAccess { 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 "";}; };
class CMachine_Download_Run_App : public AutoStateChart::CAutoStateChartMachine狀態機類需要繼承於CAutoStateChartMachine模板類,該類聲明如下:
template我們先看下這個類的成員變量。m_strCurrentState保存了狀態機在跳轉中的當前狀態,m_strCondition保存了狀態機中當前狀態之前的狀態的輸出,它用於決定狀態跳轉方向。m_MapCompositeStatesSubState用於保存狀態機中離開復合狀態時的最後狀態,即它記錄復合狀態機的淺歷史。m_spStore指向“數據庫”類對象。class CAutoStateChartMachine: public boost::enable_shared_from_this >, public CLocalStoreAccess { 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 >(); 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 > m_spStore; };
我們再看下復合狀態類的基礎模板
template因為復合狀態也是一種狀態,所以它也要有Entry和Exit兩種方法。而其Entry方法就是調用Transition方法。該模板類的Transition方法也是虛方法,這意味著繼承於該模板類的方法也要去實現Transition。class CCompositeStates: public CAutoStateChartBase { 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; };
#define STARTSTATE(state) \ do { \ boost::shared_ptrsp = boost::make_shared (); \ 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:"< 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:"< 然後復合狀態類和狀態機類只要使用這些宏去組織狀態跳轉,就可以清晰的描述過程了。