1. 简介
单例模式(Singleton)也是属于对象创建型模式的一种。通常我们可以让一个全局变量使得对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保持它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它提供一个访问该实例的方法。
单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点。
2. 结构图
![](https://i-blog.csdnimg.cn/blog_migrate/3ac1427fac0be345d1cfe322cf722c17.png)
- Singleton:定义一个Instance操作,允许客户访问它的唯一实例。Instance是一个类操作。
3. 实例分析
考虑这么一个应用场景:假如我们正在开发某个应用软件的用户交互系统,该交互系统由多个不同的交互窗口组成。为了使系统方便管理这些交互窗口,我们需要一个窗口管理器的类来对这些窗口进行管理。但同时我们希望该窗口管理器在我们的交互系统中仅有一个实例(试想下,如果在我们的交互系统中存在多个窗口管理的实例,我们还需要保证这些管理类的同步,这是麻烦而且不好处理的)。
我们怎么样才能保证一个类只有一个实例并且这个实例易于被访问呢?一个全局变量变量使得一个对象能被访问,但它不能防止你实例化多个对象。
一个更好的办法是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建(通过截取创建新对象的请求),并且它可以提供一个访问该实例的方法。这就是单例模式(Singleton)。
单例模式在实现上可以有多种写法,这里会例举出这些写法,这些写法各有利弊,具体选用哪个需要更加实际情况做分析。
3.1 懒汉式单例模式
/*********************************************************************************
*Copyright(C),Your Company
*FileName: 懒汉式单例模式.h
*Author: Huangjh
*Version:
*Date: 2017-11-04
*Description: 懒汉式单例模式的实现
*Others:
**********************************************************************************/
#ifndef _SIGNLETON_H
#define _SIGNLETON_H
#include <cstddef>
class CSingleton
{
public:
static CSingleton *Instance(void)
{
if (m_Instance == NULL)
{
m_Instance = new CSingleton();
}
return m_Instance;
}
protected:
CSingleton() { }
private:
static CSingleton *m_Instance;
};
#endif //#ifndef _SIGNLETON_H
/*********************************************************************************
*Copyright(C),Your Company
*FileName: main.cpp
*Author: Huangjh
*Version:
*Date: 2017-11-04
*Description: 单例模式的测试用例
*Others:
**********************************************************************************/
#include "懒汉式单例模式.h"
CSingleton *CSingleton::m_Instance = NULL;
int main(void)
{
CSingleton *pSingleton = CSingleton::Instance();
return 0;
}
懒汉式的单例模式声明了一个静态对象,在用户第一个调用时才将自己实例化(这里存在线程安全的问题,因此懒汉的单例模式使用于单线程环境下)。注意构造器是保护型的。试图直接实例化Singleton的客户将得到一个编译时的错误信息。这样就保证了仅有一个实例可以被创建。
另外,这边需要补充说明的是:在C++11标准之前并没有规定局部静态变量是线程安全的,如果使用的编译器支持C++11的标准,还可以这么使用:
/*********************************************************************************
*Copyright(C),Your Company
*FileName: 懒汉式单例模式.h
*Author: Huangjh
*Version:
*Date: 2017-11-04
*Description: 懒汉式单例模式的实现
*Others:
**********************************************************************************/
#ifndef _SIGNLETON_H
#define _SIGNLETON_H
#include <cstddef>
class CSingleton
{
public:
static CSingleton *Instance(void)
{
static CSingleton Instance;
return &Instance;
}
protected:
CSingleton() { }
};
#endif //#ifndef _SIGNLETON_H
3.2 饿汉式单例模式
/*********************************************************************************
*Copyright(C),Your Company
*FileName: 饿汉式单例模式.h
*Author: Huangjh
*Version:
*Date: 2017-11-04
*Description: 饿汉式单例模式的实现
*Others:
**********************************************************************************/
#ifndef _SIGNLETON_H
#define _SIGNLETON_H
#include <cstddef>
class CSingleton
{
public:
static CSingleton *Instance(void)
{
return s_Instance;
}
protected:
CSingleton() { }
private:
static CSingleton *s_Instance;
};
#endif //#ifndef _SIGNLETON_H
/*********************************************************************************
*Copyright(C),Your Company
*FileName: main.cpp
*Author: Huangjh
*Version:
*Date: 2017-11-04
*Description: 单例模式的测试用例
*Others:
**********************************************************************************/
#include "饿汉式单例模式.h"
CSingleton *CSingleton::s_Instance = new CSingleton();
int main(void)
{
CSingleton *pSingleton = CSingleton::Instance();
return 0;
}
这种方式在程序运行(main函数)之前就完成初始化。
3.3 双重锁定
/*********************************************************************************
*Copyright(C),Your Company
*FileName: 双重锁定式单例模式.h
*Author: Huangjh
*Version:
*Date: 2017-11-04
*Description: 双重锁定式单例模式的实现
*Others:
**********************************************************************************/
#ifndef _SIGNLETON_H
#define _SIGNLETON_H
#include <cstddef>
#include <boost/thread/mutex.hpp>
class CSingleton
{
public:
static CSingleton *Instance(void)
{
if (s_pInstance == NULL)
{
boost::mutex::scoped_lock(m_MutexLock);
if (s_pInstance == NULL)
{
s_pInstance = new CSingleton();
}
}
return s_pInstance;
}
protected:
CSingleton() { }
private:
boost::mutex m_MutexLock;
static CSingleton *s_pInstance;
};
#endif //#ifndef _SIGNLETON_H
/*********************************************************************************
*Copyright(C),Your Company
*FileName: main.cpp
*Author: Huangjh
*Version:
*Date: 2017-11-04
*Description: 单例模式的测试用例
*Others:
**********************************************************************************/
#include "双重锁定式单例模式.h"
CSingleton *CSingleton::s_pInstance = NULL;
int main(void)
{
CSingleton *pSingleton = CSingleton::Instance();
return 0;
}
4. 优缺点
4.1 优点
- 对唯一实例的受控访问。因为Singleton类封装它的唯一实例,所以它可以严格的控制客户怎样以及何时访问它。
- 缩小命名空间。Singleton模式是对全局变量的一种改进。它避免了那些存储唯一实例的全局变量污染命名空间。
- 允许对操作和表示的精化。Singleton类可以有子类,而且用这个扩展类的实例来配置一个应用是很容易的。
- 允许可变数目的实例。这个模式使得你易于改变你的想法,并允许Singleton类的多个实例。
- 比类操作更灵活。
5. 适用性
在下面的情况下可以使用Singleton模式
- 当类只能有一个实例而且客户可以从一个众所周知的访问点访问它们时。
- 当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
6. 参考资料
- 《大话设计模式》
- 《设计模式——可复用面向对象软件的基础》