Singleton(单例模式)

  • 一、概述
  • 1.结构
    • 2.适用场景
      • 3.优缺点
    • 二、懒汉单例模式
  • 1.线程不安全的懒汉单例模式
    • 2.线程安全的懒汉单例模式
    • 3.同步锁模式
      • 三、饿汉单例模式
      • 四、Meyers' Singleton

一、概述

只涉及一个单一的类,该类否则创建自己的对象,同时确保只有单个对象被创建。这个类提供一种方法访问唯一的对象方式,可以直接创建,不需实例化该类的对象。

保证一个类仅有一个实例,并提供一个访问它的全局访问点,主要解决一个全局使用的类频繁地创建与销毁。

1.结构

  1. 单例类声明了一个名为getInstance 获取实例的静态方法来返回其所属类的一个相同实例。

  2. 单例的构造函数必须对客户端代码隐藏。调用获取实例方法必须是获取单例对象的唯一方式。

2.适用场景

  1. 程序中只有一个可用的实例。

  2. 需要更加严格地控制全局变量,可以使用单例模式。

3.优缺点

优点:

  1. 保证一个类只有一个实例。

  2. 获得了一个指向该实例的全局访问节点。

  3. 仅在首次请求单例对象时对其进行初始化。

  4. 没有接口,不能继承。

缺点:

  1. 违反了单一职责原则。该模式同时解决了两个问题。

  2. 单例模式可能掩盖不良设计,比如程序各组件之间相互了解过多等。

  3. 该模式在多线程环境下需要进行特殊处理,避免多个线程多次创建单例对象。

  4. 单例的客户端代码单元测试可能会比较困难,因为许多测试框架以基于继承的方式创建模拟对象。由于单例类的构造函数是私有的,而且绝大部分语言无法重写静态方法,所以你需要想出仔细考虑模拟单例的方法。要么干脆不编写测试代码,或者不使用单例模式。

二、懒汉单例模式

1.线程不安全的懒汉单例模式

类加载时没有生成单例,只有当第一次调用 instance_方法时才去创建这个单例,
注意懒汉模式在不加锁情况下是线程不安全的,只适用于单线程

#include <iostream>
#include<string>using namespace std;class Singleton {private:static Singleton* instance_;//实例对象static:保证全局只有一个Singleton() {}//构造函数私有:即单例模式只能在内部私有化public://外界通过GetInstance()获取实例对象static Singleton* GetInstance() {if (instance_ == nullptr){instance_ = new Singleton();}return instance_;}
};
// 静态变量instance;静态成员必须在类外定义
Singleton* Singleton::instance_ = nullptr;int main()
{Singleton* s1 = Singleton::GetInstance();Singleton* s2 = Singleton::GetInstance();cout << "s1地址:" << s1 << endl;cout << "s2地址:" << s2 << endl;return 0;
}

2.线程安全的懒汉单例模式

上述代码并不是线程安全的,当多个线程同时调用Singleton::GetInstance(),可能会创建多个实例从而导致内存泄漏(会new多次但我们只能管理唯一的一个instance_),通过互斥锁实现线程安全。

#include <iostream>
#include<string>
#include<mutex>using namespace std;class Singleton {private:static Singleton* instance_;//实例对象static:保证全局只有一个static mutex m_mutex_;Singleton() {}//构造函数私有:即单例模式只能在内部私有化
public://外界通过GetInstance()获取实例对象static Singleton* GetInstance() {// 加锁保证多个线程并发调用getInstance()时只会创建一个实例m_mutex_.lock();if (instance_ == nullptr){instance_ = new Singleton();}m_mutex_.lock();return instance_;}
};//静态成员必须在类外定义
Singleton* Singleton::instance_ = nullptr;
mutex Singleton::m_mutex_;int main()
{Singleton* s1 = Singleton::GetInstance();Singleton* s2 = Singleton::GetInstance();cout << "s1地址:" << s1 << endl;cout << "s2地址:" << s2 << endl;return 0;
}

3.同步锁模式

适用于多线程下的懒汉模式中,每一个线程在判断instance_是否为NLL前,都先要进行加锁操作,如果此时已经有其他线程进行了加锁操作,那么当前线程就进入了阻塞状态,如此以往,就会导致大量资源被浪费,还影响了效率,其实我们只需要小小的改动,就可以解决这个问题。

#include <iostream>
#include<string>
#include<mutex>using namespace std;class Singleton {private:static Singleton* instance_;//实例对象static:保证全局只有一个static mutex m_mutex_;Singleton() {}//构造函数私有:即单例模式只能在内部私有化
public://外界通过GetInstance()获取实例对象static Singleton* GetInstance() {if(instance_==NULL){// 加锁保证多个线程并发调用getInstance()时只会创建一个实例m_mutex_.lock();if (instance_ == nullptr){instance_ = new Singleton();}m_mutex_.lock();}return instance_;}
};//静态成员必须在类外定义
Singleton* Singleton::instance_ = nullptr;
mutex Singleton::m_mutex_;int main()
{Singleton* s1 = Singleton::GetInstance();Singleton* s2 = Singleton::GetInstance();cout << "s1地址:" << s1 << endl;cout << "s2地址:" << s2 << endl;return 0;
}

将加锁和判断instance_是否为NULL 的顺序对调了一下就解决了这个问题,即当instance==NULL的时候,才去进行加锁,实例化唯一对象,解锁的操作,如果此时instance != NULL,说明唯一的对象已经被实例化出来了,那么其他线程就不需要再进行加锁,解锁操作了,而是可以直接使用这个唯一的对象。

三、饿汉单例模式

所谓的饿汉模式懒汉模式恰恰相反,懒汉模式是只有当我们需要的时候才实例化唯一的对象,而饿汉是无论你需不需要,一开始就将唯一的对象实例化出来。

#include <iostream>
#include<string>
#include<mutex>using namespace std;class Singletion {private:static Singletion* instance_;Singletion(){}
public:static Singletion* GetInstance(){return instance_;}
};
Singletion* Singletion::instance_ = new Singletion();//静态成员必须在类外定义int main()
{Singletion* s1 = Singletion::GetInstance();Singletion* s2 = Singletion::GetInstance();cout << "s1地址: " << s1 << std::endl;cout << "s2地址: " << s2 << std::endl;return 0;
}


饿汉模式的好处,就是不需要再判断instance是否为NULL了,这在某些情况下能起到非常大的作用。

四、Meyers’ Singleton

Meyers’ Singleton是Scott Meyers提出的C++单例的推荐写法。它将单例对象作为局部static对象定义在函数内部:

class Singleton {public:static Singleton& GetInstance() {static Singleton instance;return instance;}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;private:Singleton() {}
};

优点:

解决了普通单例模式全局变量初始化依赖(C++只能保证在同一个文件中声明的static遍历初始化顺序和其遍历声明的顺序一致,但是不能保证不同文件中static遍历的初始化顺序)。

缺点:

  1. 需要C11支持(C11保证static成员初始化的线程安全)。

  2. 性能问题(同懒汉模式一样,每次调用GetInstance()方法时需要判断局部static变量是否已经初始化,如果没有初始化就会进行初始化,这个判断逻辑会消耗一点性能)。

Singleton(单例模式)创建型相关推荐

  1. 设计模式(2)--Singleton(单例模式)--创建型

    1.模式定义: 单例模式确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 2.模式特点: (1)单例类只能有一个实例. (2)单例类必须自己创建自己的唯一实例. (3)单例类必须给所有 ...

  2. 单例模式——创建型模式

    2019独角兽企业重金招聘Python工程师标准>>> 思路: 当我们要写一个工具箱的窗体程序的时候我们会怎么写? //=============================== ...

  3. 创建型模式:抽象工厂

    个人博客原文: 创建型模式:抽象工厂 五大创建型模式之三:抽象工厂. 简介 姓名 :抽象工厂 英文名 :Abstract Factory Pattern 价值观 :不管你有多少产品,给我就是了 个人介 ...

  4. 创建型模式:原型模式

    前方高能:<一故事一设计模式>PDF 电子书已经上线,关注公众号即可获取. 个人公众号原文: 创建型模式:原型模式 五大创建型模式之五:原型模式. 简介 姓名 :原型模式 英文名 :Pro ...

  5. 创建型模式:建造者模式

    前方高能:<一故事一设计模式>PDF 电子书已经上线,关注公众号即可获取. 个人公众号原文: 创建型模式:建造者模式 五大创建型模式之四:建造者模式. 简介 姓名 :建造者模式 英文名 : ...

  6. C#设计模式之一单例模式(Singleton Pattern)【创建型】

    一.引言 看了李建忠老师的讲的设计模式已经有一段时间了(这段时间大概有一年多了),自己还没有写过自己的.有关设计模式的文章.这次想写一些关于设计模式的文章,用自己的理解和代码来写,算是复习一遍.写作的 ...

  7. 设计模式(21):创建型-单例模式(Singleton)

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式于 ...

  8. 八.创建型设计模式——Singleton Pattern(单例模式)

    定义 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类,它提供全局访问的方法.单例模式的要点有三个:一是某个类只能有一个实例:二是它必须自行创建这个实例:三是 ...

  9. 创建型模式--(再论)单例模式

    在 创建型模式--单例模式 一文中我们提到单例模式,就是 一个类仅有一个实例,并提供一个访问它的全局访问点. 那么问题来了,我们以上一篇中代码为例: <pre name="code&q ...

最新文章

  1. A + B Problem
  2. Web Service 安全性解决方案(SOAP篇)
  3. 医疗信息化:高可用、安全两手都要硬
  4. Spring和Mybatis整合,配置文件
  5. 2021-07-21新技术赋能数智财会,用友YonBIP财务云激活企业创新能力
  6. 机械设计基础第一章绪论精选习题(全覆盖,无死角版)2018-01-06
  7. AS(Android studio)常见问题
  8. LeetCode 1941. 检查是否所有字符出现次数相同
  9. python解析格式文件
  10. cp: 略过目录XXXXXX
  11. Git+GitHub+SaltStack
  12. 黑马python在线培训
  13. MS4200 PCI串口卡驱动
  14. 制作一个html网页的步骤,制作一个完整的网页的步骤
  15. 基于SSM酒店管理系统
  16. TVS管 与 稳压二极管参数对比
  17. 最新校招笔试面试六十题
  18. 腾讯2019技术岗笔试 小Q非常喜欢复读,有时候,小Q会得到某个字符串S。这时他会把s不断重复不断重复连成一个无限长的串。比如说,小Q现在得到一个串abc,他会直一复读, 那么形成的字符串就是:
  19. A. Sequence with Digits
  20. 一文带你快速入门【哈希表】

热门文章

  1. 港科夜闻丨香港科大吴宏伟教授:注重留学生人才培养
  2. s:action标签的使用
  3. 实现langchain-ChatGLM API调用客户端(及未解决的问题)
  4. 宽带断电后连不上网服务器无响应,为什么我家装的电信宽带一停电就连不上去...
  5. 中文编程,最精致的python访客登记系统实例项目,微信机器人不再只当人工智障------05
  6. HashMap、比较器与Lambda
  7. 一个对JAVA不熟悉导致实现造轮子的悲惨故事
  8. PL/SQL入门,非常详细的笔记
  9. mysql pk uk_「fk」SQL中PK、UK、DF、CK、FK的意思 - seo实验室
  10. win10固态硬盘分区 整数_送给“毒奶粉”以及win7党!win10如何重装win7?