一、单例模式
1、概念:
只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。
这种设计模式属于创建型模式,它提供了一种创建对象的最佳方式
**关键点:**①一个类只有一个实例(最基本的)
②它必须自行创建这个实例
③它必须给所有其他对象提供这个实例
**意图:**保证一个类仅有一个实例,并提供一个访问它的全局访问点
**主要解决:**一个全局使用的类频繁地创建与销毁
**何时使用:**当你想控制实例数目,节省系统资源的时候
**如何解决:**判断系统是否已经有这个单例,如果有则返回,没有则创建
**关键代码:**构造函数是私有的
应用实例:
①一个班级只有一个班主任。
②Window是多进程多线程的,在操作一个文件的时候,就不可避免的出现多个进程或线程同时操作一个文件的现象,所以所有的文件的处理 必须通过唯一的实例来进行。
③一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一文件
优点:
①在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如电子学院首页页面缓存)
②避免对资源的多重占用(比如写文件操作)
缺点:
没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
使用场景:
①要求生产唯一的序列号
②WEB中的计数器,不用每次刷新都在数据库中加一次,用单例先缓存起来
③创建的一个对象需要消耗的资源过多,比如I/O与数据库的连接
单例模式的实现:
构造函数声明为private或protect防止被外部函数实例化,内部保存一个private static的类指针保存唯一的实例,实例的动作由一个public的类方法代劳,该方法也返回单例类唯一的实例。
一、简单
class Singleton {
private:
Singleton(){}
static Singleton *p;
public:
static Singleton *instance();
};
Singleton *Singleton::p = nullptr;
Singleton * Singleton::instance() {
if (p == nullptr) {
p = new Singleton();
}
return p;
}
二、
#include<iostream>
#include<thread>
using namespace std;
class Singleton {
private:
Singleton(){}//构造函数private
static Singleton *single;
public:
static Singleton *GetSingleton();
};
Singleton *Singleton::single = nullptr;
Singleton *Singleton::GetSingleton() {
if (single == nullptr) {
single = new Singleton;
}
return single;
}
int main() {
//只有调用GetSingleton时,类才会new出对象
Singleton *s1 = Singleton::GetSingleton();
Singleton *s2 = Singleton::GetSingleton();
if (s1 == s2) {
cout << "s1==s2" << endl;//输出s1==s2
}
else {
cout << "s1!=s2" << endl;
}
return 0;
}
2、两种主要实现方式:
**懒汉:**顾名思义,不到万不得已就不会去实例化类,也就是说在第一次用到类实例的时候才会去实例化(懒汉模式本身是线程不安全的)
**饿汉:**单例类定义的时候就进行实例化。(本身是线程安全的)
如何选择:
懒汉:在访问量较小的时候,采用懒汉实现。这是以时间换空间。
饿汉:由于要进行线程的同步,所以在访问量比较大,或者可能访问的线程比较多时,采用饿汉模式实现,可以实现更好的性能。这是以空间换时间。
①:懒汉模式(类加载时不初始化)
线程不安全,怎么办?最直观的方法是:加锁。
方法1:加锁的经典懒汉实现
class Singleton {
private:
Singleton() {
pthread_mutex_init(&mutex);
}
static Singleton *p;
public:
static pthread_mutex_t mutex;
static Singleton *instance();
};
pthread_mutex_t Singleton::mutex;
Singleton *Singleton::p = nullptr;
Singleton *Singleton::instance() {
if (p == nullptr) {
pthread_mutex_lock(&mutex);
if (p == nullptr) {
p = new Singleton();
}
pthread_mutex_unlock(&mutex);
}
return p;
}
方法2:内部静态变量的懒汉实现
在instance函数里定义一个静态的实例,也可以保证拥有唯一实例,在返回时只需要返回其指针就可以了。(这种方法非常简单,强推)
class Singleton {
private:
Singleton() {
pthread_mutex_init(&mutex);
}
public:
static pthread_mmutex_t mutex;
static Singleton *initance();
};
pthread_mutex_t Singleton::mutex;
Singleton *Singleton::initance() {
pthread_mutex_lock(&mutex);
static Singleton obj;
pthread_mutex_unlock(&mutex);
return &obj;
}
②:饿汉模式(在类加载时就完成了初始化,所以类加载比较慢,但获取对象的速度快)
饿汉模式本身就是线程安全的,不用加锁
class Singleton{
private:
Singleton(){}
static Singleton *p;
public:
static Singleton *initance();
};
Singleton *Singleton::p = new Singleton;
Singleton *Singleton::initance() {
return p;
}