小弟从来不盲目崇拜设计模式,项目中也切忌滥用设计模式的,但是有些作用十分不错的设计模式还是应该运用的,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)