亚洲精品自拍aⅴ在线_福利一区在线视频播放_五月天婷婷亚洲熟女一区_h片 AV 在线免费观看

使用C++實現(xiàn)一套簡單的狀態(tài)機模型——原理解析

來源:互聯(lián)網(wǎng)   閱讀:-

區(qū)塊鏈
2020
03/29
06:05



在上一文中,我們介紹了該狀態(tài)機模型的使用方法。通過例子,我們發(fā)現(xiàn)可以使用該模型快速構(gòu)建滿足基本業(yè)務(wù)需求的狀態(tài)機。本文我們將解析該模型的基礎(chǔ)代碼,以便大家可以根據(jù)自己狀態(tài)機特點進行修改。(轉(zhuǎn)載請指明出于breaksoftware的csdn博客)

該模板庫的基礎(chǔ)方法實現(xiàn)在之后給出的工程的AutoStateChart.h中,該文件一共215行,其中有16行是輔助調(diào)試代碼。以上一文中狀態(tài)機類為例:

 public AutoStateChart::
CAutoStateChartMachine<CMachine_Download_Run_App, CStoreofMachine>

CMachine_Download_Run_App類繼承于模板類CAutoStateChartMachine,該模板類有兩個參數(shù):繼承類自身和CStoreofMachine。CStoreofMachine類顧名思義,其是狀態(tài)機中用于存儲數(shù)據(jù)的類。為什么要設(shè)計這樣的類?因為在我們的狀態(tài)機模型中,每個基礎(chǔ)狀態(tài)都是割裂的。這樣設(shè)計的一個好處便是我們可以讓每個基礎(chǔ)狀態(tài)的邏輯代碼獨立,和其他模塊沒有任何耦合。當(dāng)我們要刪除某個狀態(tài)時,我們只要將它從狀態(tài)機的跳轉(zhuǎn)聲明中摘除即可。當(dāng)我們要新增某個狀態(tài)時,我們也只要在狀態(tài)機跳轉(zhuǎn)中做相應(yīng)聲明即可。但是往往優(yōu)點也伴隨著缺點:它使得每個基礎(chǔ)狀態(tài)類的數(shù)據(jù)交互產(chǎn)生了障礙。特別是沒有上下文關(guān)系的基礎(chǔ)狀態(tài),跳躍性的傳遞信息將變得非常困難。于是我們就需要一個存活于整個狀態(tài)機聲明周期的“數(shù)據(jù)庫”,它可以被每個基礎(chǔ)狀態(tài)類訪問和修改。于是CStoreofMachine就應(yīng)運而生。因為該類比較獨立,所以我們先從該類開始解析。首先我們看下該類的聲明:

#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平臺,其他平臺沒論證過。其實它的內(nèi)容是非常簡單的,就是暴露成員變量的set和get方法。只是我覺得這種寫法比較有意思,才在這兒羅列下。
我們再看下該類在模板中的使用,我們先從最基礎(chǔ)的類開始解析

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,它相當(dāng)于一個默認的“數(shù)據(jù)庫”。當(dāng)模板的使用者不需要“數(shù)據(jù)庫”時,就可以在模板中不聲明“數(shù)據(jù)庫”類,此時我們的CEmptyLocalStore就生效了。比如我們上例的狀態(tài)機可以改成:

class CMachine_Download_Run_App :
public AutoStateChart::CAutoStateChartMachine<CMachine_Download_Run_App>

CLocalStoreAccess類主要提供如下作用:

設(shè)置訪問“數(shù)據(jù)庫”類對象的方法——SetStore

獲取“數(shù)據(jù)庫”類對象——GetStore

成員變量m_pFunc是一個函數(shù)指針,用于獲取“數(shù)據(jù)庫”類對象。該變量將由CLoaclStoreAccess繼承類設(shè)置,相當(dāng)于CLocalStoreAccess暴露了設(shè)置訪問“數(shù)據(jù)庫”類對象的能力。而它并不保存“數(shù)據(jù)庫”類對象——它只提供“訪問”能力,而不提供“存儲”能力。

	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就是“數(shù)據(jù)庫”類對象,即該類提供了“存儲”功能。它繼承于CLoaclStoreAccess類,使得該類具備了訪問數(shù)據(jù)庫的能力——雖然它的私有方法可以訪問“數(shù)據(jù)庫”類對象,但是我還是希望將這些能力分開。因為之后介紹的基礎(chǔ)狀態(tài)類要有“訪問”的能力,而不應(yīng)該具備“存儲”的能力。如果不將這些能力進行拆分,將會導(dǎo)致層次結(jié)構(gòu)混亂。

CLoaclStoreBase類的init方法,打通了和ClocalStoreAccess的關(guān)系——設(shè)置函數(shù)指針。

介紹完用于存儲上下文的模板類后,我們現(xiàn)在可以關(guān)注下狀態(tài)機相關(guān)的類了。我們先看上一文中一個基礎(chǔ)狀態(tài)類的例子

class CSimpleState_Download_From_A :
public AutoStateChart::CAutoStateChartBase<CSimpleState_Download_From_A, CMachine_Download_Run_App, CStoreofMachine>
CSimpleState_Download_From_A類繼承于CAutoStateChartBase模板類。第一個模板參數(shù)是繼承類自身,第二個是它所屬的狀態(tài)機,第三個是“數(shù)據(jù)庫”類。我們在看下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 "";};
};

該模板類使用第一個模板參數(shù)類的類名作為其繼承類的狀態(tài),并使用GetCurrentState方法提供獲取功能。比如上例中的狀態(tài)名為class CSimpleState_Download_From_A。這個模板類繼承于CLocalStoreAccess模板類,使得繼承類具有可以“訪問”第三個模板參數(shù)類——“數(shù)據(jù)庫”類的能力——不具備“存儲”能力。同時該類還暴露了兩個方法——Entry和Exit,他們分別用于在進出該狀態(tài)時,讓狀態(tài)機調(diào)用。

狀態(tài)和存儲類都介紹完了,我們就剩下調(diào)度狀態(tài)變化的狀態(tài)機類和復(fù)合狀態(tài)類。其實從某種程度上說,復(fù)合狀態(tài)是一種簡單的狀態(tài)機,它們在很多地方存在共性。我們從狀態(tài)機類入口,進行講解。首先看下上一文中的例子

class CMachine_Download_Run_App :
public AutoStateChart::CAutoStateChartMachine<CMachine_Download_Run_App, CStoreofMachine>

狀態(tài)機類需要繼承于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保存了狀態(tài)機在跳轉(zhuǎn)中的當(dāng)前狀態(tài),m_strCondition保存了狀態(tài)機中當(dāng)前狀態(tài)之前的狀態(tài)的輸出,它用于決定狀態(tài)跳轉(zhuǎn)方向。m_MapCompositeStatesSubState用于保存狀態(tài)機中離開復(fù)合狀態(tài)時的最后狀態(tài),即它記錄復(fù)合狀態(tài)機的淺歷史。m_spStore指向“數(shù)據(jù)庫”類對象。

該模板類最重要的函數(shù)就是StartMachine,它在第一次被調(diào)用時創(chuàng)建了“數(shù)據(jù)庫”類對象。然后死循環(huán)調(diào)用Transition方法。Tansition方法是個虛方法,它是整個模型的核心。狀態(tài)機類需要實現(xiàn)自己的Transition方法,以使得狀態(tài)機可以運轉(zhuǎn)起來。

我們再看下復(fù)合狀態(tài)類的基礎(chǔ)模板

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;
};

因為復(fù)合狀態(tài)也是一種狀態(tài),所以它也要有Entry和Exit兩種方法。而其Entry方法就是調(diào)用Transition方法。該模板類的Transition方法也是虛方法,這意味著繼承于該模板類的方法也要去實現(xiàn)Transition。

于是所有的重心都集中于Transition方法的實現(xiàn)。

為了讓代碼美觀,我參考了MFC中使用宏簡潔代碼的思路,設(shè)計了如下的宏:

#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; \
};

然后復(fù)合狀態(tài)類和狀態(tài)機類只要使用這些宏去組織狀態(tài)跳轉(zhuǎn),就可以清晰的描述過程了。

最后,如果你想學(xué)C/C++可以私信小編“01”獲取素材資料以及開發(fā)工具和聽課權(quán)限哦!

推薦閱讀:鍛煉身體的軟件app

 

THE END
本文系轉(zhuǎn)載,版權(quán)歸原作者所有;旨在傳遞信息,不代表烏魯木齊熱線的觀點和立場。

相關(guān)熱點

相關(guān)推薦