~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
方案A
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
该方案为Design Patterns所列举的最简单的一种实现方法(以下的代码
是按照我自己的编码习惯写的,但是语意上和DP里的实现没有区别):
---- Declaration A ----
class Singleton {
public:
static Singleton * instance();
protected:
Singleton();
private:
static Singleton * me;
};
---- Implementation A ----
Singleton * Singleton::me = 0;
Singleton * Singleton::instance() {
if( me == 0 )
me = new Singleton();
return me;
}
简述: 通过对默认构造函数的保护基本上实现了Singleton模式的初衷,
利用一个静态指针me来指向唯一的一个Singleton实例,同时使用
lazy initialization(中文版的DP里翻译成惰性初始化,感觉很
别扭)来延迟了Singleton对象的内存分配和构造。
使用: 将需要以Singleton模式实现的类由Singleton为基类派生即可。当然
那样的话要将Singleton的析构函数写成virtual。
缺陷: · 只将默认构造函数作为保护成员,却没有保护拷贝构造函数和
operator=(),造成了漏洞,例如如下代码:
Singleton * pFirst = Singleton::instance();
Singleton second( * pFirst );
Singleton third = second;
便创建了三个Singleton对象,使得Singleton模式被破坏。
· 没有保护析构函数,因此如果对Singleton::instance()所返回
的Singleton指针进行delete,或者通过指针显式调用析构函数,
则静态指针me将成为野指针,并且由于没有被清零,再次调用
Singleton::instance()将成为危险的动作,并可能造成复杂的
运行期错误。
补充: · 将拷贝构造和operator=()也列为protected。
· 如果Singleton对象构造后不允许被析构,则将析构函数列位
protected并定义为virtual;如果允许Singleton对象被析构和
再创建,则应该在析构函数中对静态指针me进行清零。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
方案B
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
该方案实际上只是方案A的一个简单变种:
---- Declaration B ----
class Singleton {
public:
static Singleton& instance( void ) {
static Singleton me;
return me;
}
protected:
Singleton( void ) {
}
Singleton( const Singleton& ) {
}
virtual ~Singleton( void ) {
}
const Singleton& operator=( const Singleton& ) {
}
private:
};
简述: 该方案补充了方案A的缺陷,同时利用局部静态变量,而不是作为
成员变量的静态指针来维系instance()和Singleton的唯一实例之间
的关系,从而简化了类结构,免除了一个成员变量。并且由于在且
仅在第一次调用instance()的时候,局部静态变量me才会被构造,
该方案很自然地实现了lazy initialization。同时instance()函数
的返回值由指针改为引用,防止了delete操作,当然由于析构函数
被保护,即使返回值为指针,进行delete操作也会造成编译期错误。
应该说除了下述的缺陷外,该方案的Singleton实现是比较完善的。
使用: 和方案A一样,将Singleton作为基类来使用。
缺陷: 由于是使用局部静态变量来实例化Singleton对象,虽然Singleton的
唯一实例me是在第一次调用instance()的时候构造的,但是me的内存
却是编译期确定下来的,不像方案A那样可以动态分配内存。
由此直接导致的问题就是该方案不能像方案A(的补充改进版本)
那样允许Singleton实例被析构并再次构造。因为instance()除了第一
次被调用以外,就没有再次调用Singleton构造函数的机会了。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
方案C
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
该方案的实现比较有趣,利用了模板和私有继承。事实上以下代码改编自
Boost库中的一个Singleton实作。我使用的Boost版本为1.32.0,原代码
文件位置为:
boost_1_32_0/boost/thread/detail/singleton.hpp
---- Declaration C ----
template <class Type>
class Singleton : private Type {
public:
static Type& instance( void );
private:
Singleton();
~Singleton();
};
template <class Type>
inline Singleton<Type>::Singleton() {
// ...
}
template <class Type>
inline Singleton<Type>::~Singleton() {
// ...
template <class Type>
inline Type& Singleton<Type>::instance() {
static Singleton<Type> me;
return me;
}
简述: 该方案的优点是可以轻易地对已有的、并未按照Singleton模式
封装的类实现Singleton模式。容易应用于现存的代码中。并且
不需要单独为所有需要实现Singleton模式的类建立一个以
Singleton类为基类的继承体系。
如同方案B,该方案也是利用局部静态变量的方法来存储类
的唯一实例。注意返回值类型为模板类型参数Type的引用,但是
instance()方法中实际返回的是一个Singleton<Type>的引用。
在代码中可以看出,Singleton<Type>是Type类型的一个私有继
承的子类,所以返回一个Singleton<Type>引用没有问题。这样
做可以保持Singleton对象的特性。
事实上,方案B就是对Boost库中的singleton和noncopyable
的借鉴结果。
使用: 需要一个类的Singleton实例时,调用Singleton<Type>::instance()
即可。
缺陷: 基于同方案二一样的原因,该方案也不允许已创建的Singleton实例
被析构并再次构造。不过一般来说这个限制也无关紧要,Boost库中
大量使用了这种Singleton模板。如果真的需要,就如同方案A一样,
改用作为成员变量的静态指针来关联Singleton实例即可。