<!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"Cambria Math"; panose-1:2 4 5 3 5 4 6 3 2 4; mso-font-charset:0; mso-generic-font-family:roman; mso-font-pitch:variable; mso-font-signature:-1610611985 1107304683 0 0 159 0;} @font-face {font-family:Calibri; panose-1:2 15 5 2 2 2 4 3 2 4; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-pitch:variable; mso-font-signature:-1610611985 1073750139 0 0 159 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:华文细黑; panose-1:2 1 6 0 4 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:647 135200768 16 0 262303 0;} @font-face {font-family:"/@华文细黑"; panose-1:2 1 6 0 4 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:647 135200768 16 0 262303 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:宋体; mso-fareast-theme-font:minor-fareast; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-font-kerning:1.0pt;} p {mso-style-noshow:yes; mso-style-priority:99; mso-margin-top-alt:auto; margin-right:0cm; mso-margin-bottom-alt:auto; margin-left:0cm; mso-pagination:widow-orphan; font-size:12.0pt; font-family:宋体; mso-bidi-font-family:宋体;} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:595.3pt 841.9pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:42.55pt; mso-footer-margin:49.6pt; mso-paper-source:0; layout-grid:15.6pt;} div.Section1 {page:Section1;} -->
一种较好的Singleton 设计
2010-1-17 李晓敏
在游戏设计中推荐使用的一种Singleton 类设计模式,源自《游戏编程精粹》。
通常在游戏设计中,我们对于游戏中大量的管理类(如:TextureManager 等)有三种设计方案:1. 使用多层类设计,即:使用一个全局的类,在该类中定义各种管理器类,这样就可以通过全局类实例找到所有的管理器指针,但当游戏复杂到一定程度的时候,要使用某个管理器指针,就需要不断的从根指针逐级查找,既操作麻烦又效率低下;2. 使用全局指针,即对每一个管理类都使用全局指针,这样做固然操作方便也效率高,但仍然存在一个问题,就是当程序结束时,销毁资源的时候,由于各个管理类直接的关联性,往往会出现由于管理类的销毁顺序的问题而导致的崩溃问题(由于全局类的资源释放是在程序运行时决定的,可操控性非常不便);3. 第三种方法,也就是这里要介绍的方法,就是使用Singleton 设计模式来设计类,这样既能保持类的操作方便、高效,还能完全操控类的创建和销毁,解决了前两种方法的缺点。
通常的Singleton 设计模式,即在所要实现的类中定义一个静态的类指针,并定义一个接口来动态的创建一个指向类自身的静态类实例指针,这样既能保持类的全局性,又能动态操作,这也正是Singleton 设计模式的精华。
class SingletonOrg
{
static Singleton* ms_SingletonOrg;
public:
static Singleton* GetInstance()
{
ms_SingletonOrg = new SingletonOrg;
}
//...
};
通常的游戏设计中都是在此基础上使用模板和宏来使实现更加灵活,但这样依然存在问题,就是类的创建可以灵活操控了,但类的销毁留给了编译器,要求在应用程序结束时销毁。我们通常需要比这更有力的控制,比如:某个子系统的销毁必须在另一个子系统之后等等。这样就需要追踪Singleton ,来自己销毁我们所创建的Singleton 指针。
下面是一种较好的实现方法,它通过在模板类中定义一中类型的类的静态指针,并通过继承类在基类的偏移来找到继承类的指针来追踪继承类的指针,和Singleton 设计模式的真谛是一致的。然后,我们就可以在继承类中按照设计普通类一样进行使用,只是在获取其指针的时候,调用在基类中定义的Singleton 接口即可。源码实现如下:
// Singleton Mode
// Base Singleton //--------------------------------------------
template<typename T> class Singleton
{
static T* ms_Singleton;
public:
Singleton(void)
{
assert(!ms_Singleton);
int offset = (int)(T*)1 - (int)(Singleton<T*>)(T*)1;
ms_Singleton = (T*)((int)this + offset);
}
~Singletion(void)
{
assert(ms_Singleton);
ms_Singleton = 0;
}
static T& GetSingleton(void)
{
assert(ms_Singleton);
return *ms_Singleton;
}
static T* GetSingleton(void)
{
return ms_Singleton;
}
};
template<typename T> T* Singleton<T>::ms_Singleton = 0;
// Class //---------------------------------------------------------------
class TextureMgr : public Singleton<TextureMgr>
{
public:
Texture* GetTexture(const char* name);
// ...
};
#define g_TextureMgr TextureMgr::GetSingleton()
// Using //---------------------------------------------------------------
void SomeFunction(void)
{
Texture* stone1 = TextureMgr::GetSingleton().GetTexture("stone1");
Texture* wood6 = g_TextureMgr.GetTexture("wood6");
}
从以上的源码中可以看出,我们可以通过设计这样一种Singleton 基类,就可以通过模板得到各种我们需要的管理器的操作类,既能方便、高效的使用,又能追踪管理器指针,进行动态创建和删除的操作。