前言
简介
单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
//以下援引百度百科
对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。
优点
1. 由于单例模式在内存中只有一个实例,减少了内存开支,特别是**一个对象需要频繁地创建、销毁**时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。
2. 减少了系统的性能开销,当**一个对象的产生需要比较多的资源**时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。
3. 避免对资源的多重占用。如避免对同一个资源文件的同时写操作。
4. 单例模式可以在系统设置全局的访问点,优化和共享资源访问。
缺点
1. 单例模式一般没有接口,扩展困难。不利于测试。使用场景
1. 在整个项目中需要一个共享访问点或共享数据。2.创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源。
3. 需要定义大量的静态常量和静态方法的环境。
代码实现
经典实现
class singleton
{
private:
static singleton *instance;
singleton(){}
public:
static singleton * getinstance()
{
if (instance == NULL)
instance = new singleton();
return instance;
}
};
singleton* singleton::instance = NULL;
通过代码我们便能够清晰的了解到单例模式设计的思想,首先单例类没有公开的构造器,其他类不能自行将其实例化得到一个实例,而必须通过它的静态方法getinstance()去创建一个实例。
singleton *a = singleton::getinstance();
singleton *b = a->getinstance();
singleton &c = *singleton::getinstance();
class singleton
{
private:
static singleton *instance;
singleton(){}
//CGarbo类的唯一工作就是在析构函数中删除CSingleton的实例
class CGarbo
{
public:
~CGarbo()
{
if (singleton::instance != NULL)
delete singleton::instance;
}
};
//定义一个静态成员,在程序结束时,系统会调用它的析构函数
static CGarbo Garbo;
public:
static singleton * getinstance()
{
if (instance == NULL)
instance = new singleton();
return instance;
}
};
singleton* singleton::instance = NULL;
singleton::CGarbo singleton::Garbo;
我们可以写一段测试代码来查看是否成功删除单例的实例,测试代码如下,增加了单例类的析构函数
#include<iostream>
using namespace std;
class singleton
{
private:
static singleton *instance;
singleton(){}
//CGarbo类的唯一工作就是在析构函数中删除CSingleton的实例
class CGarbo
{
public:
~CGarbo()
{
if (singleton::instance != NULL)
delete singleton::instance;
}
};
//定义一个静态成员,在程序结束时,系统会调用它的析构函数
static CGarbo Garbo;
public:
static singleton * getinstance()
{
if (instance == NULL)
instance = new singleton();
return instance;
}
~singleton()
{
cout << "delete success" << endl;
}
};
singleton* singleton::instance = NULL;
singleton::CGarbo singleton::Garbo;
int main() {
singleton *a = singleton::getinstance();
singleton *b = a->getinstance();
singleton &c = *singleton::getinstance();
}
运行结果:
delete success
线程安全
class singleton
{
private:
static singleton *instance;
singleton(){ pthread_mutex_init(&mutex,NULL); }
//CGarbo类的唯一工作就是在析构函数中删除CSingleton的实例
class CGarbo
{
public:
~CGarbo()
{
if (singleton::instance != NULL)
delete singleton::instance;
}
};
//定义一个静态成员,在程序结束时,系统会调用它的析构函数
static CGarbo Garbo;
static pthread_mutex_t mutex;
public:
static singleton * getinstance()
{
if (instance == NULL)
{
pthread_mutex_lock(&mutex);
if (instance == NULL)
instance = new singleton();
pthread_mutex_unlock(&mutex);
}
return instance;
}
};
singleton* singleton::instance = NULL;
singleton::CGarbo singleton::Garbo;
pthread_mutex_t singleton::mutex;
懒汉和饿汉
解决了线程问题后,才算是一个完整的单例模式。接下来介绍的只是不同的实现方式,大同小异,所要考虑的也不外乎是线程安全和内存管理等问题。懒汉模式
class singleton
{
private:
static singleton *instance;
singleton(){ pthread_mutex_init(&mutex, NULL); }
static pthread_mutex_t mutex;
public:
static singleton * getinstance()
{
pthread_mutex_lock(&mutex);
static singleton instance;
pthread_mutex_unlock(&mutex);
return &instance;
}
};
pthread_mutex_t singleton::mutex;
相信你一眼就看出,这种改进只不过是使用了局部静态变量,然后返回改变量的引用。这么一个微小的改动就能节省很多的代码。
饿汉模式
class singleton
{
private:
static singleton *instance;
singleton(){}
//CGarbo类的唯一工作就是在析构函数中删除CSingleton的实例
class CGarbo
{
public:
~CGarbo()
{
if (singleton::instance != NULL)
delete singleton::instance;
}
};
//定义一个静态成员,在程序结束时,系统会调用它的析构函数
static CGarbo Garbo;
public:
static singleton * getinstance()
{
return instance;
}
};
singleton* singleton::instance = new singleton;
singleton::CGarbo singleton::Garbo;