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

01创建型设计模式——单例模式

一、单例模式简介

        单例模式(Singleton Pattern)是一种创建型设计模式(GoF书中解释创建型设计模式:一种用来处理对象的创建过程的模式),单例模式是其中的一种,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。这个模式适用于那些需要一个全局唯一的对象来协调系统中的行为的情况。即在整个程序运行过程中,该类只存在一个对象(实例)。

GoF一书对单例模式的介绍

 二、单例模式的用处

单例模式常见的使用场景

  • 配置管理:全局配置管理器,确保配置只被加载一次并在全局范围内一致。
  • 日志记录:全局日志记录器,确保所有日志信息被记录在一个地方。
  • 线程池:全局线程池管理,避免多个线程池实例带来的资源浪费。
  • 数据库连接池:全局数据库连接池,统一管理数据库连接的创建和销毁

单例模式的优点包括:

1. 确保全局唯一性

  • 唯一性:单例模式确保一个类只有一个实例。这对于那些需要全局唯一的资源或管理类非常重要,例如配置管理器、日志记录器等。

  • 全局访问:单例模式提供了一个全局访问点来获取这个唯一实例,使得所有代码都可以通过统一的方式来访问该实例。

2. 控制资源访问

  • 资源管理:在某些情况下,某些资源(如数据库连接、线程池)只能由一个实例进行管理。使用单例模式可以有效地控制这些资源的创建和销毁,避免资源的重复创建和管理。

  • 性能优化:通过避免创建多个实例,单例模式可以减少系统开销和资源浪费。

3. 简化接口

  • 简化使用:由于只有一个实例,使用单例模式的类不需要考虑实例的创建和管理,使用时更简单直观。

  • 一致性:可以保证对全局状态的一致性和统一管理,减少了不同实例间的状态不一致问题。

4. 延迟实例化

  • 懒加载:通过懒汉式实现,单例模式可以实现延迟初始化(即实例在第一次使用时创建),从而提高系统启动速度并节省资源,直到确实需要实例时才创建它。

5. 避免多次实例化

  • 避免浪费:有些对象的创建和初始化代价较高,使用单例模式可以避免重复创建这些对象,从而节省计算资源和时间。

三、单例模式的设计步骤

a)私有化构造函数

b)提供一个全局的静态方法(全局访问点)

c)在类中定义一个静态指针,指向该类的对象(静态指针由全局访问点获取)

四、单例模式的两种设计方法

1)懒汉式(Lazy Initialization

这种设计方式只有在第一次使用时才会创建实例,这种方式的优点是延迟初始化。通常使用静态局部变量来实现线程安全的懒加载。

2)饿汉式(Eager Initialization

在这种实现中,单例实例在程序启动时就被创建。也就是不管有没有被使用,只要程序运行就会创建该对象。这个实现简单,但如果单例实例的创建开销较大,可能会导致程序启动变慢,且可能会浪费资源。

懒汉式代码示例:

lazy.cpp

#include <iostream>//Lazy Initialization
class Singleton {
public:// 获取单例实例的公共方法static Singleton& getInstance() {static Singleton instance; // 静态局部变量,线程安全return instance;}// 禁止复制构造函数和赋值操作符Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;// 其他成员变量和方法void doWorking() const {std::cout<<"我是懒汉式创建型设计模式——单例模式! "<<std::endl;}private:Singleton() {} // 私有构造函数};// 使用示例
int main() {Singleton& singleton = Singleton::getInstance();Singleton* ptr = &Singleton::getInstance();//判断是否调用同一个对象if ( &singleton == ptr){std::cout<<"我们是同一个对象! "<<std::endl;}else{std::cout<<"我们是不同的对象! "<<std::endl;}//调用对象的方法singleton.doWorking();ptr->doWorking();return 0;
}

运行效果

 

饿汉式代码示例:

eager.cpp

#include <iostream>//Eager Initialization
class Singleton {
public:// 获取单例实例的公共方法static Singleton& getInstance() {return instance;}// 禁止复制构造函数和赋值操作符Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;// 其他成员变量和方法void doWorking() const {std::cout<<"我是饿汉式创建型设计模式——单例模式! "<<std::endl;}private:Singleton() {} // 私有构造函数static Singleton instance; // 声明静态成员};Singleton Singleton::instance; // 定义并初始化静态成员(只要程序运行就创建该实例)// 使用示例
int main() {Singleton& singleton = Singleton::getInstance();Singleton* ptr = &Singleton::getInstance();//判断是否调用同一个对象if ( &singleton == ptr){std::cout<<"我们是同一个对象! "<<std::endl;}else{std::cout<<"我们是不同的对象! "<<std::endl;}//调用对象的方法singleton.doWorking();ptr->doWorking();return 0;
}

运行效果

3)单例模式的线程安全问题

使用饿汉式方法创建单例模式,如果不使用静态局部变量,而是使用裸指针+判断的方式创建单例,很容易引发多线程的资源竞争问题。(线程在空闲状态下可以挂起)

使用双重检查锁定(Double-Checked Locking)来确保多线程环境下的单例创建的安全性。

示例代码:

doubleLock.cpp

#include <iostream>
#include <mutex>//线程安全的双重检查锁定
class Singleton {
public:static Singleton* getInstance() {if (!instance) {std::lock_guard<std::mutex> lock(mutex);if (!instance) {instance = new Singleton();}}return instance;}// 禁止复制构造函数和赋值操作符Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;// 其他成员变量和方法void doWorking() const {std::cout<<"我是懒汉式单例模式——我使用了双重检查锁定保证我的创建安全! "<<std::endl;}private:Singleton() {} // 私有构造函数//类中声明静态变量static Singleton* instance;static std::mutex mutex;};Singleton* Singleton::instance = nullptr;    //定义并初始化指针为空
std::mutex Singleton::mutex;    //定义并初始化互斥锁// 使用示例
int main() {Singleton* singleton = Singleton::getInstance();Singleton* ptr = Singleton::getInstance();//判断是否调用同一个对象if (singleton == ptr){std::cout<<"我们是同一个对象! "<<std::endl;}else{std::cout<<"我们是不同的对象! "<<std::endl;}//调用对象的方法singleton->doWorking();ptr->doWorking();return 0;
}

运行效果

 

23种设计模式中,单例模式是比较简单的一种,但是涉及到的知识面也是很多的,比如线程、互斥、同步等。 后面我还会继续讲解其他设计模式,敬请期待啦(¬‿¬)

相关文章:

01创建型设计模式——单例模式

一、单例模式简介 单例模式&#xff08;Singleton Pattern&#xff09;是一种创建型设计模式&#xff08;GoF书中解释创建型设计模式&#xff1a;一种用来处理对象的创建过程的模式&#xff09;&#xff0c;单例模式是其中的一种&#xff0c;它确保一个类只有一个实例&#xff…...

图像分割(一)

一、概述 语义分割&#xff1a;是把每个像素都打上标签&#xff08;这个像素点是人、树、背景等&#xff09; 实例分割&#xff1a;不光要区别类别&#xff0c;还要区分类别中的每一个个体 损失函数&#xff1a;逐像素的交叉熵&#xff1b;样本均衡问题 MIOU指标&#xff1a…...

C++ 新经典:设计模式 目录(先留框架,慢慢来~)

C 新经典&#xff1a;设计模式 C 新经典&#xff1a;设计模式 C 新经典&#xff1a;设计模式第1章 设计模式与软件开发思想、编程环境介绍第2章 模板方法模式第3章 工厂模式、原型模式、建造者模式第4章 策略模式第5章 观察者模式第6章 装饰模式第7章 单件模式第8章 外观模式第…...

go之命令行工具urfave-cli

一、urfave/cli urfave/cli 是一个声明性的、简单、快速且有趣的包&#xff0c;用于用 Go 构建命令行工具。 二、快速使用 2.1 引入依赖 go get github.com/urfave/cli/v2 2.2 demo package mainimport ("fmt""log""os""github.com/ur…...

四种应用层协议——MQTT、CoAP、WebSockets和HTTP——在工业物联网监控系统中的性能比较

目录 摘要(Abstract) 实验设置 实验结果 节选自《A Comparative Analysis of Application Layer Protocols within an Industrial Internet of Things Monitoring System》&#xff0c;作者是 Jurgen Aquilina、Peter Albert Xuereb、Emmanuel Francalanza、Jasmine Mallia …...

MySQL的脏读、不可重复读、幻读与隔离级别

脏读/不可重复读/幻读 脏读 脏读(Dirty Read)发生在一个事务读取了另一个事务尚未提交的数据。如果第二个事务失败并回滚&#xff0c;第一个事务读到的数据就是错误的。这意味着数据从一开始就是不稳定或者“脏”的。 举例 事务A读取了某条记录的值为X。事务B修改该记录的值…...

程序员前端开发者的AI绘画副业之路:在裁员危机中寻找新机遇

正文&#xff1a; 在这个充满变数的时代&#xff0c;作为一名前端开发者&#xff0c;我经历了行业的起伏&#xff0c;见证了裁员危机和中年失业危机的残酷。在这样的背景下&#xff0c;我开始了利用AI绘画作为副业的探索&#xff0c;不仅为了寻求经济上的稳定&#xff0c;更是为…...

Burp Suite的使用和文件上传漏洞靶场试验

第一步&#xff1a;分析如何利用漏洞&#xff0c;通过对代码的查阅发现&#xff0c;代码的逻辑是先上传后删除&#xff0c;意味着&#xff0c;我可以利用webshell.php文件在上传到删除之间的间隙&#xff0c;执行webshell.php的代码&#xff0c;给上级目录创建一个shell.php木马…...

如何在Ubuntu中安装deepin wine版的企业微信

如何在Ubuntu中安装deepin wine版的企业微信 运行如下一条命令将移植仓库添加到系统中 wget -O- https://deepin-wine.i-m.dev/setup.sh | sh自此以后&#xff0c;你可以像对待普通的软件包一样&#xff0c;使用apt-get系列命令进行各种应用安装、更新和卸载清理了。 安装企业…...

案例:Nginx + Tomcat集群(负载均衡 动静分离)

目录 案例 案例环境 案例步骤 部署Tomcat服务器 部署Nginx服务器 实现负载均衡和读写分离 日志控制 案例 案例环境 操作系统 IP 地址 角色 CentOS 192.168.10.101 Nginx服务器&#xff08;调度器&#xff09; CentOS 192.168.10.102 Tomcat服务器① CentOS 1…...

【密码学】密码协议的分类:②认证协议

密码协议的分类有很多种方式&#xff0c;这里我采取的是基于协议实现的目的来分类。可以将密码协议分成三类&#xff1a;认证协议、密钥建立协议、认证密钥建立协议。 一、认证协议是什么&#xff1f; 认证协议都在认证些什么东西呢&#xff1f;认证一般要认证三个东西&#x…...

异步编程(Promise详解)

目录 异步编程 回调函数 回调地狱 Promise 基本概念 Promise的特点 1.Promise是一种构造函数 2.Promise接收函数创建实例 3.Promise对象有三种状态 4.Promise状态转变不可逆 5.Promise 实例创建即执行 6.Promise可注册处理函数 7.Promise支持链式调用 Promise的静…...

DjangoORM注入分享

DjangoORM注入 简介 ​ 这篇文章中&#xff0c;分享一些关于django orm相关的技术积累和如果orm注入相关的安全问题讨论。 ​ 攻击效果同数据库注入 从Django-Orm开始 开发角度 ​ Django ORM&#xff08;Object-Relational Mapping&#xff09;是Django框架中用于处理数…...

【HBZ分享】Redis各种类型的数据结构应用场景

String(字符串类型) 计数器&#xff1a; incr / decr, 比如商品库存&#xff0c;业务号的发号器业务数据key-value缓存&#xff0c; 缓存结果数据&#xff0c;提高网站性能&#xff0c;缓解DB压力分布式session会话&#xff0c; 集群环境下存储token鉴权信息分布式锁&#xff…...

anaconda创建并且配置pytorch(完整版)

&#x1f4da;博客主页&#xff1a;knighthood2001 ✨公众号&#xff1a;认知up吧 ** &#x1f383;知识星球&#xff1a;【认知up吧|成长|副业】介绍** ❤️如遇文章付费&#xff0c;可先看看我公众号中是否发布免费文章❤️ &#x1f64f;笔者水平有限&#xff0c;欢迎各位大…...

高级java每日一道面试题-2024年8月10日-网络篇-你对跨域了解多少?

如果有遗漏,评论区告诉我进行补充 面试官: 你对跨域了解多少? 我回答: 跨域问题&#xff0c;即Cross-Origin Resource Sharing&#xff08;CORS&#xff09;&#xff0c;是现代Web开发中一个非常重要的概念&#xff0c;涉及到浏览器的安全策略——同源策略&#xff08;Same…...

AtCoder Beginner Contest 365 A~E

A.Leap Year&#xff08;思维&#xff09; 题意&#xff1a; 给你一个介于 1583 1583 1583和 2023 2023 2023之间的整数 Y Y Y。 求公历 Y Y Y年的天数。 在给定的范围内&#xff0c; Y Y Y年的天数如下&#xff1a; 如果 Y Y Y不是 4 4 4的倍数&#xff0c;则为 365 365 …...

多机部署, 负载均衡-LoadBalance

目录 1.负载均衡介绍 1.1问题描述 1.2什么是负载均衡 1.3负载均衡的一些实现 服务端负载均衡 客户端负载均衡 2.Spring Cloud LoadBalancer 2.1快速上手实现负载均衡 2.2负载均衡策略 自定义负载均衡策略 3.服务部署&#xff08;Linux&#xff09; 3.1服务构建打包…...

(回溯) LeetCode 78. 子集

原题链接 一. 题目描述 给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的 子集 &#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&…...

DQL数据查询语言(多表处理)—/—<7>

一、多表处理 当前有两个表&#xff0c;一个是学生表student&#xff0c;一个是分数表score student表字段名表示如下&#xff08;共1000条数据&#xff09;&#xff1a; score表字段表示如下&#xff08;共6000条数据&#xff09;&#xff1a; 1、求每个学生的总分 SELECT …...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文&#xff5c;DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色&#xff0c;华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型&#xff0c;能助力我们轻松驾驭 DeepSeek-V3/R1&#xff0c;本文中将分享如何…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

【JVM】Java虚拟机(二)——垃圾回收

目录 一、如何判断对象可以回收 &#xff08;一&#xff09;引用计数法 &#xff08;二&#xff09;可达性分析算法 二、垃圾回收算法 &#xff08;一&#xff09;标记清除 &#xff08;二&#xff09;标记整理 &#xff08;三&#xff09;复制 &#xff08;四&#xff…...

C++实现分布式网络通信框架RPC(2)——rpc发布端

有了上篇文章的项目的基本知识的了解&#xff0c;现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...