[设计模式]创建模式-单例(C++描述)
second60 20180425
单例是23种设计模式中最常用的,没有之一。
1. 什么是单例?
一句话,单例就是一个全局变量(对象)。在整个程序生命周期,只有一个实例。
单例的实现很简单。
2. 单例结构图
3. 简单单例
在C++中,用static 函数和static变量来实现或用模来来继承。
3.1代码一(static 成员变量版)
class Singleton
{
public:
static Singleton* instance()
{
if(_instance == NULL) _instance = new Singleton();
return _instance;
}
private:
static Singleton* _instance;
Singleton(){} // 不能被外面实例化
~Singleton(){}
};
Singleton* Singleton::_instance() = 0;
使用:
Singleton::instance();
3.2代码二(指针版)
class Singleton
{
public:
static Singleton* instance()
{
static Singleton* _instance = NULL; // 指针
if(_instance) _instance = new Singleton();
return _instance;
}
private:
Singleton(){}
~Singleton(){}
};
使用:
Singleton::instance();
3.3代码三(不用指针版)
class Singleton
{
public:
static Singleton* instance()
{
static Singleton _instance; // 非指针
return &_instance;
}
private:
Singleton(){}
~Singleton(){}
};
使用:
Singleton::instance();
3.4 代码四(模版)
template <class T>
class Singleton
{
private:static T* m_pInstance;
Singleton(const Singleton& src){}
Singleton &operator=(const Singleton& src){};
protected:
//使继承者无法public构造函数和析构函数
Singleton(){}
~Singleton(){}
public:
static T* getInstance()
{
if (m_pInstance == NULL) //判断是否第一次调用
m_pInstance = new T();
return m_pInstance;
}
};
template <class T>
T* Singleton<T>::m_pInstance = NULL;
使用方法:
class A : public Singleton<A>{};
上面给出四种简单单例,很多种吧~~你是否还能想到更多的。使用看个人喜欢,我比较喜欢使用第二三种,因为化码量会少很多。第四种模版类,在大系统架构时用的比较多。
网上很多说法:
饥饿模式的单例:程序启动时就实例化
懒汉模式的单例:调用时再实例化单例
3.5 优缺点
优点:都提供了全局唯一的实现,实现了全局类。
缺点:上面四种只是实例了单了,但是并没有处理多线程中的问题,是线程不安全的,多个线程调用,初始化对象可能会调用多次
4 线程安全单例
怎么做到线程安全呢?当然是加锁了,所以又提出了双重检查锁机制,即在创建单例对象时,两次判断加锁。
4.1 代码一(static变量)
class Singleton
{
private:
static Singleton* m_instance;
Singleton(){}
public:
static Singleton* getInstance();
};
Singleton* Singleton::getInstance()
{
if(NULL == m_instance)
{
Lock();
if(NULL == m_instance)
{
m_instance = new Singleton;
}
UnLock();
}
return m_instance;
}
4.2代码二
class Singleton
{
private:
Singleton(){}
public:
static Singleton* instance()
{
Lock();
static SingletonInside instance;
UnLock();
return instance;
}
};
4.3 代码三(饿汉模式)
class Singleton
{
private:
static const Singleton* m_instance;
Singleton(){}
public:
static const Singleton* getInstance()
{
return m_instance;
}
};
const Singleton* Singleton::m_instance = new Singleton;
4.4 线程安全单例总结
关于线程安全,其实最主要是因为创建时,多个线程可能会同时实例化类,所以采用了锁机制,在第一个线程进入实例化时,加锁,创建后释放。
所以采用饿汉模式,是不会有上面的创建问题,因为饿汉模式在程序启动时已创建,所以在性能要求比较高时,避免频繁加锁,造成开销大。
当然,如果是关系到单例类内部成员的同步问题,还是需要加锁滴。因为数据才能同步。不会两个线程拿到单例后,交叉更改数据造成不同步。
5 运用场景
单例是运用的最广泛的设计模式,说说运用的场景:
a) 公共配置,如果整个程序只有一份的配置,通常都是单例
b) 工具类,如果是一个工具类,通常也是用单例或static方法
c) 公共数据,整个程序只有一份数据,通常用单例来维护
d) 全局变量
e) 所有想程序生命周期只有一个实例的类
6 总结
单例,平时用的最多了,不总结还不知道,一总结吓一跳,其实单例的实现方法很多,如果在单线程中,是不用考虑线程安全的;但如果是在多线程中,需要考虑下多线程安全的问题,如双重检查机制或饿汉模式,看运用场景。
快下班了,今天又贡献了一篇,开开心心分享!