简介
单例模式(Singleton Pattern,又称单件模式),是一种使用非常广泛的设计模式。其目的是为了保证一个类之某程序中有且只有一个实例,并且提供了一个全局访问的接口,即该实例是被程序共享的。
单例模式的类图:
单例模式的特征:
1. 私有化它的构造函数,以防止外界创建该类的实例;
2. 使用类的私有静态变量指针指向类的唯一实例;
3. 使用一个共有的静态方法获取该类的实例。
单例模式实现的方式
1.饿汉式
何为饿汉式?就是在正常情况下,程序进行初始化的时候,已将该对象实例化。后续使用的时候不需要进行初始化。
class Singleton
{
private:
static Singleton* instance;
private:
Singleton() {};
~Singleton() {};
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
public:
static Singleton* getInstance()
{
return instance;
}
};
//initialize defaultly
Singleton* Singleton::instance = new Singleton();
饿汉式的单例对象实在程序的main函数之前进行初始化的,所以是不存在线程安全问题的。
2.懒汉式
何为懒汉式?就是在正常情况下,我需要用到该对象的时候,才会去初始化该对象(即,在第一次使用的时候被初始化)。
class Singleton
{
private:
static Singleton* instance;
private:
Singleton() {};
~Singleton() {};
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
public:
static Singleton* getInstance()
{
if(instance == NULL)
instance = new Singleton();
return instance;
}
};
// init static member
Singleton* Singleton::instance = NULL;
3.线程安全方式
在使用多线程的时候,若用到懒汉式的方式去实现单例,那么会出现线程不安全的情况;假设有两个线程,pthread_1刚判断完 intance 为NULL 为真,准备创建实例的时候,切换到了pthread_2, 此时pthread_2也判断intance为NULL为真,创建了一个实例,再切回pthread_1的时候继续创建一个实例返回,那么此时就不再满足单例模式的要求了, 既然这样,是因为多线程访问出的问题,那我们就来加把锁,使得线程同步;
class Singleton
{
private:
static Singleton* instance;
static pthread_mutex_t mutex;
private:
Singleton() {};
~Singleton() {};
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
public:
static Singleton* getInstance()
{
if (NULL == instance ){
pthread_mutex_lock(&mutex)
if(instance == NULL)
instance = new Singleton();
pthread_mutex_unlock(&mutex)
}
return instance;
}
};
pthread_mutex_t singleton::mutex;
// init static member
Singleton* Singleton::instance = NULL;
4.泛编方式
template <typename T>
class Singleton {
public:
static T* GetInstance(){
static std::once_flag s_flag;
std::call_once(s_flag, [&](){
singleton_ptr.reset(new T);
});
return singleton_ptr.get();
}
protected:
Singleton(){};
~Singleton(){};
private:
static std::shared_ptr<T> singleton_ptr;
Singleton(const Singleton&) = delete;
Singleton&operator=(const Singleton&) = delete;
}; // end singleton
template<typename T> std::shared_ptr<T> Singleton<T>::singleton_ptr;
该方式里面用到了一些C11中的知识,例如std::shared_ptr,std::once_flag,std::call_once;这种方式的优势在于,当某一程序中需要多个不同类型的单例对象的时候,不需要再实现相应的方法,直接继承该类就可以了。如下所示:
class TestClass: public Singleton<TestClass> {
public:
TestClass();
~TestClass();
};
使用场合
- 系统只需要一个实例对象,或者考虑到资源消耗的太大而只允许创建一个对象;
- 客户调用类的单个实例只允许使用一个公共访问点,除了该访问点之外不允许通过其它方式访问该实例 (就是共有的静态方法).