Singleton模式的模板方式

作者在 2010-05-02 15:55:27 发布以下内容
单键为大多数熟知,咱们这次使用模板的方式来完成这个工作
template<typename T>
class Singleton
{
public:
 Singleton(void){}
 virtual ~Singleton();
 static T* InstancePtr(void);
 static T& Instance(void);
private:
 static T* m_pSingle;
};
template<typename T>
T* Singleton<T>::m_pSingle = 0;
template<typename T>
T& Singleton<T>::Instance( void )
{
 return *(InstancePtr());
}
template<typename T>
T* Singleton<T>::InstancePtr( void )
{
 if (m_pSingle==0)
 {
  m_pSingle = new T();
 }
 return m_pSingle;
}
template<typename T>
Singleton<T>::~Singleton()
{
 if (m_pSingle!=0)
 {
  delete m_pSingle;
 }
}
以上便是一个单键的模板基类,在使用时,比如有一个对象管理器ObjectManager类,希望把它做成单键,可以如下实现
 
class ObjectManager:public Singleton<ObjectManager>
{
......
void FunTest(void){std::cout<<"单键调用FunTest()!"<<std::endl;}
}
 
那么在使用,如此实现:
ObjectManager::InstancePtr()->FunTest();
或是:
ObjectManager::Instance().FunTest();
 
题外话:
我碰到有人在使用单键时的错误使用,如:
ObjectManager tempObjV;
tempObjV->FunTest();
这种使用并不错,但它违背的单键的思想,单键模式是希望一个全局唯一存在的对象存在,并不希望出现第二份,而且在这个第二份里的数据,可能和第一份的不同,调用会引起不必要的逻辑错误。
单键模式就是一个编程约定,就是告诉使用者,我不希望看到第二个我,但使用者有时候并不会老老实实去看你的代码,也就会不禁意中,又创建了一个ObjectManager,有一个委屈求全的方法,就是对于单键类里的函数,我们在实现它们时,如果有用到单键自己的成员变量和成员函数时,使用ObjectManager::Instance()来调用,而不是使用 this来调用,不过,这样的做法并不好看,而且也会出现浪费的内存(第二份里的成员变量占着内存却根本不会用到)。再想个办法吧,在单键成员函数里,第一行都加上this和单键指针的比较断言,这样在运行时就会报出错误,从而知道使用者在什么地方使用错误,从而修改BUG。
以上的方法好象都不是很保险,如何让这样错误在编译期暴露出来并及时地更正呢?只好将单键类的构造函数、拷贝构造函数、等号操作符重载这几个函数声明为私有的并不实现它们,那么如果使用者企图生成一个对象,编译时就会报错。但这样却让单键的InstancePtr函数里也无法生成该静态对象了,这如何是好呀,现在只好让元友这个东西上场了,在ObjectManager类里声明一个元友来解决这个问题:
friend SingleTest* Singleton<SingleTest>::InstancePtr(); 
这样InstancePtr函数就可以成功编译通过了。
修改后的类
class SingleTest:public Singleton<SingleTest>
{
public :
 ~SingleTest(void);
 void FunTest(void);
 friend SingleTest* Singleton<SingleTest>::InstancePtr(); 
private:
 SingleTest(void);
 SingleTest(const SingleTest& tSingle);
};
阅读所得 | 阅读 2043 次
文章评论,共0条
游客请输入验证码
文章归档
最新评论