最近在改良计算器 abacus 的代码,想把其中的一些类限制为单实例(即只能创建一个对象)。其实我个人并不喜欢设计模式,因为这些模式比较复杂,而且实现代码臃肿。C++ 要实现的机制通常是两个选择:要么由程序员来完成,要么由机器来完成。但 C++ 是为开发大型软件而设计的,所以它总是假定人是容易犯错的,比如名字空间。
好了,闲话少叙,单实例模式在设计模式的书中已经有很多的讨论,我今天说的是我的感受,而且我对于书上的实现不是很满意,做了一个小小的变动。
单实例模式要解决的问题是如何限制一个类只能创建唯一的对象,由于对象在创建的时候会自动调用构造函数,所以只要把构造函数声明为 private 就可以防止对类的随意构造,而需要的这个唯一的对象则可以这样创建: 为类添加一个 private 的 static 指针(以保存本类的唯一实例的地址),然后再添加一个公用的 static 的成员函数 GetInstance(),在函数内部检查指针是否为空,是则为此指针 new 一个对象就并返回这个指针。实现代码如下:
class Singleton
{
private: // 私有化构造函数
Singleton(){}
~Singleton(){}
public: // 提供外部访问唯一对象的方法
static Singleton *GetInstance()
{
if(!pInstance) pInstance = new Singleton;
return pInstance;
}
static void DestroyInstance(){if(pInstance) {delete pInstance;}}
private:
static Singleton *pInstance;
};
Singleton* Singleton::pInstance = NULL; //类体外初始化静态成员
这就是设计模式的书上所讲的方法,但是这样有一些问题,最严重的是如何程序中有好多类都需要限制单实例(比如计算器 abacus 中的词法分析器、语法分析器、计算器、日志服务等),那么不得不为每一个类都添加这样的逻辑,这想必是一件枯燥无味的事。最好是将做一个基类,使得从此类继承下来的类都只能创建一个对象,这个想法不错,利用 C++ 提供的类模板,可以写出如下的实现:
#define DECLARE_SINGLETON(type) \
protected: \
type(); \
~type();
template<class T>
class Singleton
{
DECLARE_SINGLETON(Singleton)
public: // 提供外部访问唯一对象的方法
static T *GetInstance()
{
if(!pInstance) pInstance = new Singleton;
return pInstance;
}
static void DestroyInstance(){if(pInstance) {delete pInstance;}}
private:
static T* pInstance;
};
template<class T>
Singleton* Singleton<T>::pInstance = NULL; //类体外初始化静态成员
最上面那个宏的作用是把某个类的默认构造函数声明为受保护的,然后把自己需要限制单实例的类从它继承,像下面这样使用:
#include "Singleton.h"
class MyClass : public Singleton<MyClass>
{
DECLARE_SINGLETON(MyClass)
public:
// member functions.......
private:
// member data......
};
这样似乎比较完美了,但是有一个瑕疵,就是它把默认的构造函数私有化了,顺便把构造函数的函数体也写成空的了,如果我真想在构造函数中完成一些初始化的工作,又该怎么办呢,有两个思路,一是不要那个 DECLARE_SINGLETON 的宏声明,自己手动把类的构造函数声明为 private,这样的缺点是如果忘记了这一点,而写成了 public 的话,那么前面的工作全部白费了;另一个思路是强制提供一个初始化函数,在DECLARE_SINGLETON 所声明的默认构造函数体中调用此初始化函数,然后在自己的类内部实现这个初始化函数,这样倒是可以防止前面的问题,但代价是自己的类要做更多的工作。
<全文完>