设计模式--单例模式(Singleton Pattern)
一、什么是单例模式
单例模式是一种创建型设计模式,它旨在确保一个类只有一个实例,并提供一个全局访问点来访问该实例。换句话说,单例模式限制了类的实例化次数为一个,并提供一种在应用程序中共享一个实例的方式。这对于需要只有一个实例来管理某些资源或状态的情况非常有用。
单例模式通常涉及以下几个核心概念:
- 私有构造函数(Private Constructor):单例类的构造函数被声明为私有,这意味着外部无法直接通过构造函数来创建类的实例。
- 静态成员变量(Static Member Variable):单例类通常会包含一个静态成员变量,用于保存唯一的实例。
- 静态成员函数(Static Member Function):通过静态成员函数来获取单例实例。这个函数通常负责检查是否已经有实例存在,如果没有则创建一个新的实例,并返回该实例。
通过实现单例模式,可以确保在应用程序中只有一个全局的实例,这对于资源共享、状态管理、配置信息等情况非常有用。然而,需要注意在多线程环境下实现单例模式可能会带来线程安全的问题,因此需要采取适当的措施来确保线程安全性。
二、单例模式代码样例
当实现单例模式时,我们需要确保类只有一个实例,并且提供全局访问点来获取该实例。以下是一个用C++实现的简单单例模式的代码样例:
#include <iostream>class Singleton {
private:static Singleton* instance; // 静态成员变量,保存唯一实例Singleton() {// 私有构造函数,防止外部实例化std::cout << "Singleton instance created." << std::endl;}public:// 静态成员函数,获取单例实例static Singleton* getInstance() {if (instance == nullptr) {instance = new Singleton();}return instance;}void doSomething() {std::cout << "Singleton is doing something." << std::endl;}
};Singleton* Singleton::instance = nullptr; // 初始化静态成员变量int main() {Singleton* singleton1 = Singleton::getInstance();Singleton* singleton2 = Singleton::getInstance();if (singleton1 == singleton2) {std::cout << "singleton1 and singleton2 are the same instance." << std::endl;}singleton1->doSomething();return 0;
}
在这个例子中,Singleton 类有一个私有的静态成员变量 instance 用于保存唯一实例。构造函数是私有的,这样外部无法实例化。通过静态成员函数 getInstance 来获取单例实例,如果实例不存在,则创建一个新实例。其他成员函数可以在实例上执行操作。
需要注意的是,这种简单的实现在多线程环境下可能会出现问题,因为在并发情况下可能会创建多个实例。为了确保线程安全,可以使用互斥锁或者其他同步机制。
当在单例模式中面临多线程环境时,需要确保线程安全。以下是一个使用互斥锁(mutex)来实现线程安全的单例模式样例:
#include <iostream>
#include <mutex>class Singleton {
private:static Singleton* instance;static std::mutex mutex; // 互斥锁Singleton() {std::cout << "Singleton instance created." << std::endl;}public:static Singleton* getInstance() {std::lock_guard<std::mutex> lock(mutex); // 在获取实例时加锁if (instance == nullptr) {instance = new Singleton();}return instance;}void doSomething() {std::cout << "Singleton is doing something." << std::endl;}
};Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex; // 初始化互斥锁int main() {Singleton* singleton1 = Singleton::getInstance();Singleton* singleton2 = Singleton::getInstance();if (singleton1 == singleton2) {std::cout << "singleton1 and singleton2 are the same instance." << std::endl;}singleton1->doSomething();return 0;
}
三、使用单例模式需要注意的问题
使用单例模式时需要注意以下几点:
- 线程安全性:如果在多线程环境中使用单例模式,确保实现线程安全,以防止多个线程同时创建实例。可以使用互斥锁、双检锁等方法来保证线程安全。
- 延迟实例化:单例模式通常在第一次使用时创建实例。如果实例化过早,可能会造成资源浪费。只有在需要时才创建实例,这种延迟实例化的方式可以提高性能和效率。
- 内存泄漏:由于单例模式的实例在整个应用程序生命周期内存在,如果不适当地管理实例,可能会导致内存泄漏。在程序结束时,应该正确地销毁实例。
- 全局状态:由于单例模式提供了全局访问点,可能导致过度使用全局状态。过多地使用全局状态可能会导致代码难以维护,因此应该谨慎使用单例模式。
- 单一职责原则:尽量确保单例类只负责管理单一的实例,而不应该涉及过多的业务逻辑。将不同的功能拆分到不同的类中,以遵循单一职责原则。
- 反射和序列化:一些编程语言和环境支持反射和序列化,这可能会破坏单例模式。为了避免这种情况,可以通过禁用类的克隆、序列化等方式来保护单例的独特性。
- 测试难度:由于单例模式的全局状态,可能会导致测试变得困难,因为在不同的测试用例之间共享状态可能会产生副作用。为了更好地进行单元测试,可以使用依赖注入等技术。
总之,单例模式在适当的情况下是非常有用的,但也需要谨慎使用,以避免潜在的问题和复杂性。了解单例模式的优缺点,并根据具体情况来决定是否使用它。

相关文章:
设计模式--单例模式(Singleton Pattern)
一、什么是单例模式 单例模式是一种创建型设计模式,它旨在确保一个类只有一个实例,并提供一个全局访问点来访问该实例。换句话说,单例模式限制了类的实例化次数为一个,并提供一种在应用程序中共享一个实例的方式。这对于需要只有…...
postgis数据库从一张表中过滤出一部分数据到新表中
你可以使用以下步骤在PostGIS数据库中过滤objectid<100的数据,并将其创建为新表:打开PostGIS数据库的终端或客户端工具(如Psql)。 选择你要过滤数据的表。假设表名为"original_table",该表包含一个名为&q…...
INDEMIND:“大+小”多机协同,实现机器人商用场景全覆盖
随着商用清洁机器人进入越来越多的场景中,单一的中型机器人并不能有效覆盖所有区域,更加细分化的产品组合正在成为新的趋势。 产品形态的“新趋势” 在商用场景中,目前的商用清洁机器人几乎均是中大型的产品形态,较大的体型意味…...
微信开发之一键创建标签的技术实现
简要描述: 添加标签 请求URL: http://域名地址/addContactLabel 请求方式: POST 请求头Headers: Content-Type:application/jsonAuthorization:login接口返回 参数: 参数名必选类型说明…...
八一参考文献:[八一新书]许少辉.乡村振兴战略下传统村落文化旅游设计[M]北京:中国建筑出版传媒,2022.
八一参考文献:[八一新书]许少辉.乡村振兴战略下传统村落文化旅游设计[M]北京:中国建筑出版传媒,2022....
ChatGPT⼊门到精通(7):GPT3.5与 4.0区别
⼀、详细区别 1 项⽬ GPT3.5 GPT4.0 2 打字速度 较慢,⾼峰期更慢 更加慢,差别不⼤ 3 掉线⼏率 经常掉线 很少掉线 4 分段能⼒ ⽣成⼏百字后就停⽌了, 需要回复“继续”,有时候不 是很连贯 基本连贯 5 使⽤限制 1⼩时100次提问&am…...
Springboot整合MyBatisPlus框架操作MySQL
1、MyBatis-Plus概述 MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 【技术储备】 拥有 Java 开发环境以及相应 IDE…...
基于Jenkins构建生产CICD环境(第二篇)
基于Jenkins自动打包并部署Tomcat环境 传统网站部署的流程 在运维过程中,网站部署是运维的工作之一。传统的网站部署的流程大致分为:需求分 析-->原型设计-->开发代码-->提交代码-->内网部署-->内网测试-->确认上线-->备份数据-->外网更新…...
ioctl、printk及多个此设备支持
一、ioctl操作实现 ioctl(Input/Output Control)是一个在 Unix-like 操作系统中的系统调用,用于控制设备或文件的各种操作。它允许用户空间程序与内核空间进行交互,执行一些特定的设备控制、状态查询或其他操作,而不必…...
电脑每次开机杀毒软件报iusb3mon.exe病毒已清除,电脑中病毒iusbmon杀毒办法,工具杀毒
不知道什么时候开始,我电脑C盘的系统数据存储文件夹programdata 不知不觉就没了,找不到了 programdata文件夹为存储系统数据文件的,这个文件不见了,而且我打开了显示隐藏文件和文件夹还是没有显示 然后我重启电脑,杀毒…...
centos服务器系统下安装python3并与自带的python2
centos服务器系统下安装python3并与自带的python2 在centos中,自带有python2,因此需要经常安装python3。但是这里有一个坑,就是centos的yum是用python2写的,如果正常编译安装python3,那么yum就会直接挂了。为了方便以…...
(二十)大数据实战——Flume数据采集的基本案例实战
前言 本节内容我们主要介绍几个Flume数据采集的基本案例,包括监控端口数据、实时监控单个追加文件、实时监控目录下多个新文件、实时监控目录下的多个追加文件等案例。完成flume数据监控的基本使用。 正文 监控端口数据 ①需求说明 - 使用 Flume 监听一个端口&am…...
AutoCAD图如何保存为Word
AutoCAD图如何保存为Word 引言AutoCAD图保存为Word文件步骤: 引言 不知道大家有没有是否遇到需要将AutoCAD图保存到Word中。有些小伙伴可能直接截图插入Word中,这种方法简单,但对于有高清图片需求的小伙伴就不适用了。接下来我就为大家介绍一…...
Java线程 - 详解(2)
一,线程安全问题 有些代码在单个线程的环境下运行,完全正确,但是同样的代码,让多个线程去执行,此时就可能出现BUG,这就是所谓的 "线程安全问题"。举一个例子: public class Demo {s…...
事务特性 - 达梦数据库
达梦数据库事务特性 1 事务特性1.1 原子性1.2 一致性1.3 隔离性1.4 持久性 1 事务特性 事务必须具备什么属性才是一个有效的事务呢?一个逻辑工作单元必须表现出四种属性,即原子性、一致性、隔离性和持久性,这样才能成为一个有效的事务。DM 数…...
axios 使用FormData格式发送GET请求
如果你需要使用,FormData格式,发送GET请求 将参数拼接到 FormData对象 中,使用 URLSearchParams 将FormData对象转换为查询参数字符串,并将其拼接到URL中,这样就能以FormData格式发送GET请求给服务器 注意࿱…...
CS144(2023 Spring)Lab 1: stitching substrings into a byte stream
文章目录 前言其他笔记相关链接 1. Getting started2. Putting substrings in sequence2.1 需求分析2.2 注意事项2.3 代码实现 3. 测试与优化 前言 这一个Lab主要是实现一个TCP receiver的字符串接收重组部分。 其他笔记 Lab 0: networking warmup Lab 1: stitching substri…...
【PHP】常用的PHP内置函数
1、PHP内置函数非常丰富,用于执行各种任务。以下是一些常用的PHP内置函数: 字符串操作函数: strlen(): 返回字符串的长度。 strpos(): 查找字符串中的某个子串第一次出现的位置。 substr(): 返回字符串的子串。 str_replace(): 替换字符串中的…...
css自学框架之消息弹框
首先我们还是看看消息弹框效果: 主要实现代码分为三部分 一、CSS部分,这部分主要是定义样式,也就是我们看到的外表,主要代码: /* - 弹窗 */notice{top: 0;left: 0;right: 0;z-index: 10;padding: 1em;position: fix…...
42、Flink 的table api与sql之Hive Catalog
Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
