设计模式之单例(C++版)

单例是一种常见的设计模式,用来表示一个系统中存在的独立并且唯一的对象实例,比如一个绘图的对象,维护列表的对象,等等。单例其实是模拟了C语言中的全局变量的作用,但是要比它更健壮安全。我们先看一个C++版的单例

#ifndef SINGLETON_H_
#define SINGLETON_H_
#include <stdio.h>
template<typename T>
class Singleton 
{
public:
    static T * Instance()
    {
        if (_instance == NULL)
        {
            _instance = new T();
        }
        return _instance;
    }

protected:
    Singleton(){}
private:
    static T* _instance;
};

template<typename T>
T* Singleton<T>::_instance = NULL;
#endif

首先,我们定义了一个类模板,怎样从这个模板得到单例对象呢?很简单,只需要从这个类派生出一个子类,像下边这样

class AppList:public Singleton<AppList>
{
private:
    AppList(){}
    friend class Singleton<AppList>;
public: 
  ...
  int getCount(){return 5;}
};

这样可以这么引用

...
int n = AppList::Instance()->getApCount();
...

使用起来还是很方便的。

接下来我们探讨一下技术实现。

从类模板开始,为了实现通用的单例算法,这里使用了模板,好处就不多说了,大部分的算法都会采用这种方式的(当然模板也有缺点的)。

这个模板是怎么样保证单例的?主要是通过以下几个要点,

在模板中将构造函数声明为protected。访问属性声明为protected的函数(或方法),只有类内部或者派生类内部才能访问,当我们用 A *a = new A();或者A a;这种常见的方式来实例化对象时,编译器检测到这个类的构造函数是带保护属性的,不能被对象访问,就会拒绝为该类产生实例,这样,也就避免了直接创建实例的可能。

在模板中声明一个私有静态的实例对象的指针作为唯一对象的引用,由于这个指针是私有的,不能被外界访问和操作,于是在模板中提供了一个public 的静态方法Instance()来初始化并返回这个对象指针,注意,因为不能直接初始化对象实例,只能从这个函数得到一个唯一实例的指针,所有对这个类方法的访问只能通过这个接口,这就是单例模式。

从派生类实例对象。直接从类模板得到的单例是没用的,因为它不包含其他数据。所以我们可以在类模板的基础上,创建一个派生类,把数据放到派生类里边。将派生类的构造函数设置为私有,强化了派生类的单例特性。这里的友元函数是为了让派生类能够访问父类提供的静态方法。

 

上面的单例技术,在多线程的时候并不是很安全,如果是在这种情况下,需要加锁以及多次判断等技巧,若有高手可以阐述一下。

posted @ 2014-05-12 08:14  Lodovico  阅读(200)  评论(0)    收藏  举报