本篇着重分析一下,在Ogre引擎中单件模式是如何被运用的,也就是Ogre::Singleton类的分析和使用。在开始之前,再次感叹一下,高手写的东西就是不一样,不仅仅照顾了不同的编译器,(GCC),还照顾了VC编译器的不同版本其中有一个地方这样写道:
#if defined( _MSC_VER ) && _MSC_VER < 1200
int offset = (int)(T*)1 - (int)(Singleton <T>*)(T*)1;
ms_Singleton = (T*)((int)this + offset);
#else
ms_Singleton = static_cast< T* >( this );
娘的,第二行和第三行是什么意思?分析了半天,我猜,应该是和下面那一句的等价的。是为了那些早期的VC编译器,不支持static_cast方法的编译器,提供一个静态转换的方法,今天也算是学到东西了- -,居然可以这样做静态转换。去掉一些乱起八糟的我看不懂但是还可能有用的东西,剩下的“干货”是酱紫的。
#pragma once
#include "OgrePrerequisites.h"
namespace Ogre {
/** Template class for creating single-instance global classes. */
template <typename T> class Singleton
{
protected:
static T* ms_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; }
};
}
是滴,Ogre声明了一个基类,Singleton,它同时是一个模板类,所有需要单件模式的实体类,可以继承这个基类,通过继承的方式得到单件模式。例如,号称是“万物之源”的Root类都继承了Singleton类。这个对咱来说还是有点新,可能是咱太弱弱了吧。写了一个Demo来作为Ogre单件模式的分析演示程序。简要代码如下:
//-----Singleton.h-----------基类--模板类-----------------
#pragma once
#include <iostream>
using namespace std;
//模板基类的单件模式演示:
namespace hawkwang{
template<typename T>
class Singleton
{
protected:
static T* ms_Singleton;
public:
Singleton(void){
assert(!ms_Singleton);
ms_Singleton = static_cast< T* >(this);
cout<<"Singleton constructor!"<<endl;
}
~Singleton(void){
assert(ms_Singleton);
ms_Singleton = 0;
}
static T* getSingletonPtr(void){
return ms_Singleton;
}
static T& getSingleton(void){
assert(ms_Singleton);
return (*ms_Singleton);
}
};
}
这里需要注意一下,ms_Singleton 一定是一个静态成员变量,同理,getSingleton和getSingletonPtr方法也是一样,静态的类。
//---------BananaTree.h---香蕉树类头文件,实体类------
#pragma once
#include "Singleton.h"
namespace hawkwang{
class BananaTree:public Singleton<BananaTree>
{
public:
BananaTree();
~BananaTree();
void Banana();
static BananaTree* getSingletonPtr(void);
static BananaTree& getSingleton(void);
};
}
//-----BananaTree.cpp---橡胶类的源文件----------------------
#pragma once
#include "stdafx.h"
#include "BananaTree.h"
#include <iostream>
using namespace std;
namespace hawkwang{
template<> BananaTree* Singleton<BananaTree>::ms_Singleton = 0;
BananaTree& BananaTree::getSingleton(){
assert(ms_Singleton);
return (*ms_Singleton);
}
BananaTree* BananaTree::getSingletonPtr(){
return ms_Singleton;
}
BananaTree::BananaTree(){cout<<"Constructor of BananaTree"<<endl;}
BananaTree::~BananaTree(){cout<<"Destructor of BananaTree"<<endl;}
void BananaTree::Banana(){cout<<"I am a lovely Banana"<<endl;}
}
//-------------AppleTree.h----苹果树类的头文件,实体类------
#pragma once
#include "Singleton.h"
namespace hawkwang{
class AppleTree:public Singleton<AppleTree>{
public:
AppleTree();
~AppleTree();
void Apple();
static AppleTree& getSingleton(void);
static AppleTree* getSingletonPtr(void);
};
}
//------AppleTree.cpp----苹果树类源代码--------
#pragma once
#include "stdafx.h"
#include "AppleTree.h"
#include <iostream>
using namespace std;
namespace hawkwang{
template<> AppleTree* Singleton<AppleTree>::ms_Singleton = 0;
AppleTree* AppleTree::getSingletonPtr(){return ms_Singleton;}
AppleTree& AppleTree::getSingleton(){assert(ms_Singleton); return (*ms_Singleton);}
AppleTree::AppleTree(){cout<<"Constructor of AppleTree"<<endl;}
AppleTree::~AppleTree(){cout<<"Destructor of AppleTree"<<endl;}
void AppleTree::Apple(){cout<<"I am a lovely Apple"<<endl;}
}
//--------main函数---------------------------------
#include "stdafx.h"
#include "BananaTree.h"
#include "AppleTree.h"
#include <iostream>
using namespace hawkwang;
int _tmain(int argc, _TCHAR* argv[])
{
BananaTree bananaRoot;
AppleTree appleRoot;
BananaTree::getSingleton().Banana();
AppleTree::getSingleton().Apple();
char c;
std::cin>>c;
return 0;
}
喔喔,果然高手写的东西就是不一样啊。通过一个模板类,使Singleton类作为其他类的基类,所有需要单件模式的实体类,只需要继承SIngleton类,并实现getSingleton,和getSingletonPtr方法即可。注意,初始化基类ms_Singleton静态成员变量的方法:
template<> AppleTree* Singleton<AppleTree>::ms_Singleton = 0;
注意,静态成员函数在AppleTree类还要再声明一边!因为是静态的拉……。那么,单件是怎么样体现出来的呢?看SIngleton类的代码:
assert(!ms_Singleton);
这个断言,如果Singleton已经被赋值了,再次调用构造函数的时候,这个断言为假,这时候,就会报错了。这个看似粗暴的方式,实现了通过模板基类和派生的方式的单件模式。灵活性的代价,就是粗暴……,但是确实可以有效的保证继承了SIngleton类的派生类只有一个实例。
访问单件的方法,很简单“类名::getSingleton”“类名::getSingletonPtr”注意SIngleton类只是为了实现单件,而不是为了多态性,所以,不要试图用Singleton类当接口,以多态的方式操作他的派生类。