当前位置: 首页 > article >正文

【设计模式】单例模式

一,定义

单例模式:创建型模式之一,是指在内存中只会创建且仅创建一次对象的设计模式。在程序中多次使用同一个对象且作用相同时,为了防止频繁地创建对象使得内存飙升,单例模式可以让程序仅在内存中创建一个对象,让所有需要调用的地方都共享这一单例对象。

二,核心思想

只能有一个实例,有懒汉和饿汉区分,实现核心思想:

1.构造函数私有化

2.使用静态函数作为接口来获取类对象

三,分类

  1. 懒汉式

  • 真正需要使用对象时才去创建该单例类对象

1.1概念

懒汉式创建对象的方法是在程序使用对象前,先判断该对象是否已经实例化(判空),若已实例化直接返回该类对象,否则则先执行实例化操作。

1.2实现

//懒汉式
class Singleton_lazy
{
private:
    Singleton_lazy() {}
    Singleton_lazy(const Singleton_lazy&) = delete;
    Singleton_lazy& operator=(const Singleton_lazy&) = delete;
public:
    static Singleton_lazy* getInstance() //线程不安全
    {
        if (pSingleton == nullptr)
        {
            pSingleton = new Singleton_lazy;
        }
        return pSingleton;
    }
private:
    static Singleton_lazy* pSingleton;
};
Singleton_lazy* Singleton_lazy::pSingleton = nullptr;

1.3步骤总结

  • 先将构造函数设置为私有属性,保证外界不能创建单例对象

  • 删除拷贝构造,防止通过单例对象创建新对象

  • 删除赋值重载,避免出现值语义的拷贝

  • 定义 静态 私有 单例类指针对象

  • 定义静态公有成员方法,保证外界可以获取单例对象,并函数内动态构建单例对象

1.4问题

这样的写法会出现下面的问题:

1.5正确的懒汉式写法

为了解决线程不安全问题,我们需要对懒汉式的getInstance方法重写

使用 Double Check(双重校验) + Lock(加锁)

双重校验:

第一次if判断是为了提高代码效率

第二次if判断是为了防止别的线程进入到if和new之间,从而多次创建实例

class Singleton_lazy
{
private:
    Singleton_lazy() {}
    Singleton_lazy(const Singleton_lazy&) = delete;
    Singleton_lazy& operator=(const Singleton_lazy&) = delete;
public:
    static Singleton_lazy* getInstance()
    {
        if (pSingleton == nullptr)  //第一次校验
        {
            mut.lock();  //加锁
            if (pSingleton == nullptr)   //第二次校验
            {
                pSingleton = new Singleton_lazy;
            }
            mut.unlock();  //解锁
        }
        return pSingleton;
    }
private:
    static Singleton_lazy* pSingleton;
    static mutex mut;  //定义锁
};
Singleton_lazy* Singleton_lazy::pSingleton = nullptr;
mutex Singleton_lazy::mut;

1.6优缺点

优点

  • 不执行getInstance()就不会被实例,资源利用率高

缺点

  • 第一次加载时不够快,需要使用额外资源(锁)

  1. 饿汉式

  • 类加载时,就已经创建好单例对象,等待被程序调用

2.1概念

饿汉式在类加载时已经创建好该对象,在程序调用时直接返回该单例对象。

即是程序开始之前在数据区创建一个静态对象,保证该单例对象的唯一性。

2.2实现

//饿汉式
class Singleton_hungry
{
private:
    Singleton_hungry() {}
    Singleton_hungry(const Singleton_hungry&) = delete;
    Singleton_hungry& operator=(const Singleton_hungry&) = delete;
public:
    static Singleton_hungry* getInstance()
    {
        return pSingleton;
    }
private:
    static Singleton_hungry* pSingleton;
};
Singleton_hungry* Singleton_hungry::pSingleton = new Singleton_hungry;

2.3步骤总结

  • 先将构造函数设置为私有属性,保证外界不能创建单例对象

  • 删除拷贝构造,防止通过单例对象创建新对象

  • 删除赋值重载,避免出现值语义的拷贝

  • 定义 静态 私有 单例类指针对象

  • 定义静态公有成员方法,保证外界可以获取单例对象

  • 类外动态创建单例对象

2.4优缺点

优点:

  • 线程安全

  • 对象提前创建好,直接调用就可以,效率高

缺点:

  • 提前创建对象会占用一定的内存空间

四,适用场景

  1. 需要频繁实例化适用然后销毁的对象

  1. 频繁访问数据库或文件的对象


http://www.kler.cn/a/4421.html

相关文章:

  • 在VS2022中用C++连接MySQL数据库读取数据库乱码问题
  • 【C语言】线程----同步、互斥、条件变量
  • 使用docker-compose安装Redis的主从+哨兵模式
  • golang运维开发-gopsutil(2)
  • Qt 自动根据编译的dll或exe 将相关dll文件复制到目标文件夹
  • Python使用socket实现简易的http服务
  • 蓝桥杯冲刺 - week1
  • ESP IDF docker 使用方法
  • C语言基础——运算符(定义变量、转义字符、输入输出语句、运算符、32个关键字)
  • 【华为OD机试 2023最新 】 识图谱新词挖掘(C++)
  • 用户态--fork函数创建进程
  • vue 监听器及计算属性高阶用法
  • vue Teleport和ref结合复用弹框组件
  • 统计字符串中每个字符出现的次数
  • C语言基础——流程控制语句
  • 深度学习的面试小记
  • VUE3 学习笔记(五)UI框架Element Plus
  • C/C++开发,编译环境搭建
  • HDFS概述
  • 查看mysql InnoDB引擎 线程模型信息
  • Modelsim仿真使用教程
  • Leetcode.1191 K 次串联后最大子数组之和
  • 数据结构之小端和大端之谜
  • Vue 点击图片放大显示功能
  • 11_nginx_document_uri
  • 信息打点-主机架构蜜罐识别WAF识别端口扫描协议识别服务安全