【设计模式】单例模式代码设计

目录

  • 单例模式简介
  • 饿汉单例模式
  • 懒汉单例模式
  • 线程安全的懒汉单例模式

橙色
详细可参考该篇文章:C++设计模式 - 单例模式

单例模式简介

单例模式指的是,无论怎么获取,永远只能得到该类类型的唯一一个实例对象,那么设计一个单例就必须要满足下面三个条件:

1、构造函数私有化,这样用户就不能任意定义该类型的对象了
2、定义该类型唯一的对象
3、通过一个static静态成员方法返回唯一的对象实例

饿汉单例模式

饿汉式单例模式,顾名思义,就是程序启动时就实例化了该对象,并没有推迟到第一次使用该对象时再进行实例化

为什么getInstance成员函数要加static关键字?因为普通成员方法的调用还是要依赖于对象,但现在没对象,现在是通过接口来获取对象的,所以 返回唯一的对象实例的函数 应该是静态成员函数。

下面这个是饿汉式单例模式:

#include 
using namespace std;
/*
单例模式:
饿汉式单例模式:还没有获取实例对象,实例对象就已经产生了
懒汉式单例模式:唯一的实例对象,直到第一次获取它的时候,才产生
*/

//饿汉式单例模式,一定是线程安全的
class Singleton
{
public:
    static Singleton* getInstance()//#3 获取类的唯一实例对象的接口方法
    {
        return &instance;
    }
private:
    static Singleton instance;//#2 定义一个唯一类的实例对象
    Singleton()     //#1 构造函数私有化
    {

    }
    Singleton(const Singleton &) = delete;
    Singleton &operator=(const Singleton&) = delete;
};

Singleton Singleton::instance;

int main()
{
    Singleton *p1 = Singleton::getInstance();
	Singleton *p2 = Singleton::getInstance();
	Singleton *p3 = Singleton::getInstance();
    cout << p1 << " " << p2 << " " << p3 << endl;
    return 0;
}

在这里插入图片描述

但有时呢,可能你整个任务过程中都没有试图获取过该单例对象,但函数是先于程序执行载入的,那么可能饿汉模式,先定义了一个唯一的实例对象,并且构造函数进行了大量的初始化,所以在程序启动时就会先创建出一个实例化对象,白白浪费很多时间。所以有时就会用懒汉模式

懒汉单例模式

下面这个是懒汉式单例模式,把对象的实例化延迟到第一次获取该实例对象时。在程序启动时,它仅仅先创建了一个指针而不是一个对象

可重入函数:在多线程中能够被不同线程重复调用,即一个线程调用还没结束时,另一个线程又来调用,这样的函数就称为可重入函数

#include 
using namespace std;

/*
单例模式:
饿汉式单例模式:还没有获取实例对象,实例对象就已经产生了
懒汉式单例模式:唯一的实例对象,直到第一次获取它的时候,才产生
*/

//懒汉式单例模式,存在线程安全的问题
class Singleton
{
public:
    static Singleton* getInstance()//#3 获取类的唯一实例对象的接口方法
    {
        if(instance==nullptr)
        {
            instance = new Singleton();
        }
        return instance;
    }
private:
    static Singleton *instance;//#2 定义一个唯一类的实例对象
    Singleton()     //#1 构造函数私有化
    {

    }
    Singleton(const Singleton &) = delete;
    Singleton &operator=(const Singleton&) = delete;
};

Singleton* Singleton::instance=nullptr;

int main()
{
    Singleton *p1 = Singleton::getInstance();
	Singleton *p2 = Singleton::getInstance();
	Singleton *p3 = Singleton::getInstance();
    cout << p1 << " " << p2 << " " << p3 << endl;
    return 0;
}

在这里插入图片描述

线程安全的懒汉单例模式

饿汉单例模式中,单例对象定义成了一个static静态对象,它是在程序启动时,main函数运行之前就初始化好的,因此不存在线程安全问题,可以放心的在多线程环境中使用。但上面的懒汉模式代码却不是安全的

在静态成员变量instance的前面加volatile关键字,是因为在多线程中cpu为了加快速度,往往会将静态成员变量的值都拷贝一份,带到各个的线程中去,放到cpu的缓存里。而加了volatile,加了该关键字后,就禁止了各个线程拷贝该变量。如果该静态成员变量的值发生改变,那么所有的线程都会立刻看到静态成员变量的改变

下面是线程安全的懒汉单例模式:

#include 
#include
using namespace std;

/*
单例模式:
饿汉式单例模式:还没有获取实例对象,实例对象就已经产生了
懒汉式单例模式:唯一的实例对象,直到第一次获取它的时候,才产生
*/

mutex mtx;
//懒汉式单例模式=》是不是线程安全的呢?=》线程安全的懒汉式单例模式    
class Singleton
{
public:
    //是不是可重入函数呢?  锁+双重判断
    static Singleton* getInstance()//#3 获取类的唯一实例对象的接口方法
    {
        //lock_guard guard(mtx);//在这里加锁锁的粒度太大了,如果是单线程的话,调用该函数还是要每次加锁解锁
        if(instance==nullptr)
        {
            lock_guard<mutex> guard(mtx);
            if(instance==nullptr)
            {
                /*
                开辟函数
                构造函数私有化
                给instance赋值
                */
                instance = new Singleton();
            }   
        }
        return instance;
    }
private:
    static Singleton *volatile instance;//#2 定义一个唯一类的实例对象
    Singleton()     //#1 构造函数私有化
    {

    }
    Singleton(const Singleton &) = delete;
    Singleton &operator=(const Singleton&) = delete;
};

Singleton*volatile Singleton::instance=nullptr;

int main()
{
    Singleton *p1 = Singleton::getInstance();
	Singleton *p2 = Singleton::getInstance();
	Singleton *p3 = Singleton::getInstance();
    cout << p1 << " " << p2 << " " << p3 << endl;
    return 0;
}

在这里插入图片描述

当然,线程安全的懒汉模式还有另一种写法,如下:

#include 
#include
using namespace std;

/*
单例模式:
饿汉式单例模式:还没有获取实例对象,实例对象就已经产生了
懒汉式单例模式:唯一的实例对象,直到第一次获取它的时候,才产生
*/

//懒汉式单例模式
class Singleton
{
public:
    //仅在第一次调用该函数的时候,才会创建该对象
    static Singleton* getInstance()//#3 获取类的唯一实例对象的接口方法
    {
        //函数静态局部变量的初始化,在汇编指令上已经自动添加了线程互斥指令了
        static Singleton instance;
        return &instance;
    }
private:
    Singleton()     //#1 构造函数私有化
    {

    }
    Singleton(const Singleton &) = delete;
    Singleton &operator=(const Singleton&) = delete;
};


int main()
{
    Singleton *p1 = Singleton::getInstance();
	Singleton *p2 = Singleton::getInstance();
	Singleton *p3 = Singleton::getInstance();
    cout << p1 << " " << p2 << " " << p3 << endl;
    return 0;
}

在这里插入图片描述

你可能感兴趣的:(设计模式,单例模式,设计模式)