小弟從來不盲目崇拜設計模式,項目中也切忌濫用設計模式的,但是有些作用十分不錯的設計模式還是應該運用的,Ogre在這方面就十分不錯,設計模式篩選的十分得當,代碼也十分優雅,對我影響很大,以至於我現在的代碼風格完全改變爲Ogre式的風格。
由於要設計整個客戶端的框架,所以靈活運用Ogre的一些設計模式對項目的幫助也是很大的。
先從單件入手吧,
爲什麼需要singleton,因爲每個相對獨立的模塊都應該有一個總類來管理,這個總類應該是唯一的,而且最好是靜態的,這樣在其他類中調用就十分方便。
唯一和靜態,這2個需求我們可以通過這樣實現
class Manager
{
public:
Manager(void) { smSingelton = this; }
static Manager* getSingletonPtr(void) { return smSingelton; }
static Manager& getSingleton(void) { assert(smSingelton); return *smSingelton; }
protected:
static Manager* smSingelton;
};
Manager* Manager::smSingelton = NULL;
但是如果有很模塊,需要很多個單件的管理器,最好就應該用模板來管理,Ogre就是類似這樣實現的
template <typename T> class Singleton
{
public:
Singleton( void )
{
assert( !ms_Singleton );
ms_Singleton = static_cast<T*>(this);
}
~Singleton( void )
{ assert( ms_Singleton ); ms_Singleton = 0; }
static T& getSingleton( void )
{ assert( ms_Singleton ); return ( *ms_Singleton ); }
static T* getSingletonPtr( void )
{ return ( ms_Singleton ); }
protected:
static T* ms_Singleton;
};
然後要用的時候只需要繼承這個單件模板類,重寫getSingleton函數:
class WindowManager : public Singleton <WindowManager>
{
// 重寫
static WindowManager* MaterialManager::getSingletonPtr(void)
{
return ms_Singleton;
}
static WindowManager& MaterialManager::getSingleton(void)
{
assert( ms_Singleton ); return ( *ms_Singleton );
}
}
然後在頭文件初始化靜態變量ms_Singleton;
template<> WindowManager* Singleton<WindowManager>::ms_Singleton = NULL;
---------------------------------------------------------------------------------------------------------------------------
上面的用法很簡單,但是如果你在外部用Ogre的單件模板類可能會遇到一個問題,就是dll導出模板類的問題
因爲Ogre是dll庫,dll動態庫是不能導出模板類的,應該模板是編譯時候決定類型的,但是dll是可以導出實例的模板類的,
改一下重寫的代碼,直接調用基類的函數:
class WindowManager : public Singleton <WindowManager>
{
// 重寫
static WindowManager& WindowManager::getSingleton(void)
{
return Singleton<WindowManager>::getSingleton();
}
static WindowManager* WindowManager::getSingletonPtr(void)
{
return Singleton<WindowManager>::getSingletonPtr();
}
}
最後,細節問題,到底我們該調用getSingleton還是getSingletonPtr
答案就是getSingleton更好,因爲getSingleton獲得引用必須是有斷言的安全校驗的,getSingletonPtr是沒有
注:上面的代碼都沒有添加dll的__declspec(dllexport)