什么是单例模式
单例模式最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
我们需要注意以下几点:
1. 单例类只能有一个实例。
2. 单例类必须自己创建自己的唯一实例。
3. 单例类必须给所有其他对象提供这一实例。
我们在以下环境中使用这种模式:
当一个类在整个项目中都需要频繁的访问(全局访问),在每次调用时都要创建一次对象(频繁创建),在每次调用完后都要销毁一次(频繁销毁),那么对性能的负担特别大,这个时候,我们的单例模式就需要用在这种环境下。
单例模式的实例代码如下(代码可以左滑查看全部):
新建一个类 Singleton,在 Singleton.h中:
class Singleton{
public:
//构造函数
Singleton();
//初始化单例
static void Initialize();
// 供外部获取的指针
static Singleton* Get();
private:
// 创建单例
static Singleton& Create();
private:
// 指向单例本身的静态指针
static Singleton* SingletonPtr;
}
在 Singleton.cpp中
#include "Singleton.h"
// 单例的实现
Singleton::SingletonPtr = NULL;
void Initialize(){
// 检查指针是否存在
if (SingletonPtr == NULL) {
// 不存在就创建
SingletonPtr = Create();
}
}
Singleton::Get() {
// 初始化单例
Initialize();
// 返回这个指针
return SingletonPtr;
}
Singleton::Create() {
// 创建这个单例
Singleton& SingletonRef = new Singleton();
// 返回这个单例
return SingletonRef;
}
我们在调用这个单例的时候只需调用这个单例的Get()函数即可。
但是,我们的这个单例模式在多线程的情况下是不安全的,因为在多线程的情况下,存在多个线程在同一时间同时调用Get()函数,此时我们的单例指针SingletonPtr一直为空,也就会被多个线程同时创建,这样就违反了我们单例模式的设计原则。
我们可以通过对Initialize函数加上线程锁的方式来解决这个问题,代码如下:
// 线程锁
static mutex mut;
void Initialize(){
// 上锁
mut.lock();
// 检查指针是否存在
if (SingletonPtr == NULL) {
// 不存在就创建
SingletonPtr = Create();
}
// 解锁
mut.unlock();
}
但是这样在每个线程访问的时候都要上一个锁,对资源的消耗也是不小,于是我们可以多加一层判断来解决这个问题,代码如下:
// 线程锁
static mutex mut;
void Initialize(){
if (SingletonPtr == NULL){
// 上锁
mut.lock();
// 检查指针是否存在
if (SingletonPtr == NULL) {
// 不存在就创建
SingletonPtr = Create();
}
// 解锁
mut.unlock();
}
}
这样加了一层判断以后,我们只需要在单例指针SingletonPtr为空的情况下才对锁进行判断,当单例指针有值的情况下则不进行上锁解锁的操作。