设计模式——Singleton(单例)设计模式
摘要
本文介绍了单例设计模式的概念、实现和应用场景。单例模式确保某个类只有一个实例,节省资源并提供全局访问点。文章详细解释了单例模式的实现要素,包括私有构造方法、静态实例和公共静态方法,并探讨了其在数据库连接池、日志记录器和配置管理器等场景中的应用。
1. 单例设计模式是什么
1.1. 单例模式理解
单例设计模式(Singleton Pattern)是一种常见的创建型设计模式,旨在确保某个类在整个应用程序中只有一个实例,并提供一个全局访问点。这个模式的主要目的就是控制类的实例化过程,避免在程序运行期间多个实例的创建。它在需要全局唯一实例时非常有用,例如配置管理器、日志记录器等。
1.2. 单例模式核心概念
单例模式的核心概念就是 唯一性 和 全局访问,通过私有化构造方法、提供全局访问点、延迟实例化、确保线程安全等手段来实现其目标。通过使用单例模式,可以有效地控制类的实例化和资源管理,避免冗余实例的创建。
单例设计模式的核心概念是确保某个类在整个应用程序中只有一个实例,并且提供一个全局访问点来访问该实例。其核心思想可以总结为以下几点:
- 唯一性:单例模式的主要目的是保证某个类只有一个实例。在程序的整个生命周期中,无论调用多少次获取实例的方法,都只能返回同一个实例。这避免了系统中多个相同对象的存在,确保了资源的统一管理和共享。
- 全局访问:单例模式提供一个全局访问点,使得该唯一实例可以在系统的任何地方被访问。通常这个访问点是通过一个静态方法实现的,外部通过该方法访问实例,而不需要直接创建实例。
- 延迟初始化:虽然单例模式保证了唯一性,但通常在实际使用时,实例的创建是延迟的(即懒加载)。实例只有在第一次被访问时才会被创建。这样可以避免在程序启动时就创建实例,节省资源,提升性能。
- 私有构造方法:为了确保类只能创建一个实例,单例模式通常会将构造方法设为私有的,阻止外部直接调用构造方法创建实例。这样,外部只能通过提供的静态方法来获取实例。
- 线程安全:在多线程环境下,需要保证实例的创建是线程安全的,防止多个线程同时创建多个实例。因此,单例模式在实现时需要考虑线程同步,以避免并发问题。
- 避免反射和序列化破坏单例:为了防止反射攻击或者序列化和反序列化破坏单例模式,一些实现方式(如枚举方式)能够防止通过反射创建新的实例。通过这种方式,确保了单例模式的安全性。
1.3. 单例设计模式作用
单例设计模式的作用可以总结为以下三点:
- 确保唯一性:单例模式保证某个类只有一个实例,避免了多个实例造成的资源浪费和管理混乱。例如,数据库连接池通常使用单例模式来确保在整个应用中只创建一个连接池实例,避免了多次创建和销毁连接池的开销。
- 提供全局访问点:单例模式通过静态方法提供一个全局访问点,使得系统的各个部分可以共享和访问该唯一实例。例如,日志记录器类通常使用单例模式,确保全局只有一个日志实例,且所有模块都通过该实例记录日志。
- 节省资源:单例模式通常采用懒加载(延迟实例化)策略,只有在第一次需要时才创建实例,从而节省系统资源。例如,配置管理器类可以使用单例模式来确保只加载一次配置文件,而不是每次读取时都创建新的实例。
2. 单例设计模式类实现
我们通过一个单例类 来确保该类只有一个实例,并且提供一个全局访问点来获取该实例。单例模式的实现通常需要包含以下几个核心要素:
- 私有构造方法:禁止外部通过构造方法直接创建实例。
- 静态实例:持有类的唯一实例。
- 公共静态方法:提供一个公共的访问点来获取唯一实例。
3. 单例模式使用场景
在实际工作中,单例模式有着广泛的应用,尤其是在需要确保全局唯一实例、共享资源或进行全局配置管理的场景。以下是几个常见的单例模式具体使用场景,并说明每个场景的作用:
3.1. 数据库连接池
场景:在开发大型系统时,数据库连接池通常会使用单例模式。一个数据库连接池是一个可以复用数据库连接的对象,在系统中通常只需要一个池来管理所有的数据库连接。通过单例模式,可以确保连接池在应用程序中只有一个实例,避免每次数据库操作都创建新的连接池实例,降低系统开销。
作用:
- 确保唯一性:通过单例模式,数据库连接池在整个应用中只有一个实例,避免了多次创建池的开销。
- 资源共享:确保多个数据库操作共享同一个连接池实例,提高连接的复用率,节省系统资源。
- 性能优化:通过连接池管理,可以减少数据库连接的创建和销毁的成本,提升系统的性能。
3.2. 日志记录器
场景:系统中的日志记录器通常使用单例模式来确保全局只有一个日志实例。日志系统需要将日志记录到文件或数据库等地方,如果每个模块都实例化一个新的日志对象,不仅浪费内存,还可能导致日志信息混乱。
作用:
- 确保唯一性:确保整个系统中只有一个日志记录器实例,避免了多个日志对象的创建。
- 全局共享:所有模块通过该单一日志实例记录日志,确保日志格式和记录方式的一致性。
- 降低内存消耗:避免了不必要的日志对象创建和销毁,提高了系统资源的利用率。
3.3. 配置管理器(RocketMQTemplate等类)
场景:配置文件(如数据库连接配置、系统参数等)在整个应用程序中可能被多个模块使用。配置管理器通常使用单例模式,确保所有模块都访问同一个配置实例,而不是每次都重新加载配置文件。
作用:
- 确保唯一性:只有一个配置管理器实例,避免了重复加载配置文件的资源浪费。
- 全局访问:提供全局访问点,允许各个模块获取配置数据而无需重新读取文件或数据库。
- 提高性能:减少重复读取配置文件的次数,提升系统性能。
3.4. 线程池管理(线程池创建)
场景:线程池用于管理线程的创建、销毁和复用,确保在多线程环境下能够合理使用系统资源。线程池通常实现为单例模式,以确保全局只有一个线程池实例来处理所有任务。
作用:
- 确保唯一性:整个系统共享同一个线程池实例,避免了多个线程池对象造成的资源浪费。
- 线程管理:通过线程池集中管理线程,避免了每次任务执行时都创建新线程的开销。
- 提升性能:通过复用线程,提高了任务执行效率,减少了频繁创建和销毁线程的成本。
3.5. 缓存管理(Redis配置类)
场景:在一些高性能的应用中,经常使用缓存来存储频繁访问的数据。缓存系统(例如 Redis 缓存管理器)通常会实现为单例模式,以确保整个应用中只有一个缓存实例,所有组件都能共享同一个缓存。
作用:
- 确保唯一性:通过单例模式,缓存系统只有一个实例,避免了多个实例占用多余的内存。
- 全局共享:多个模块可以访问同一个缓存实例,提高缓存命中率,减少重复计算。
- 性能优化:缓存数据减少了对数据库或其他资源的访问,提高了系统性能。
3.6. 事件分发系统
场景:在一些事件驱动的系统中,可能会有一个全局的事件分发系统,用来管理和分发各个组件之间的事件通知。此时,可以使用单例模式来确保事件分发系统在整个应用中只有一个实例。
作用:
- 确保唯一性:确保事件分发系统只会有一个实例,避免了事件处理混乱和资源浪费。
- 全局访问:允许所有模块通过单一的事件分发器进行事件的发布和监听,确保事件流的一致性。
- 高效管理:集中管理事件,提高了系统的可维护性和扩展性。
3.7. 应用程序状态管理
场景:在一些需要跟踪全局应用状态的系统中(例如,用户登录状态、权限管理等),可以使用单例模式来管理应用程序的全局状态。
作用:
- 确保唯一性:保证全局状态管理只有一个实例,避免多个状态实例导致的不一致性。
- 简化管理:通过单一实例,简化应用状态的管理和共享,减少了不同模块之间的状态同步问题。
- 提高一致性:通过集中管理应用状态,保证整个系统的状态一致性。
4. 单例设计模式的示例(Spring)
public class MyLogUtil {public static void debug(Logger logger, String message) {debug(logger, message, (Object[])null);}public static void debug(Logger logger, String message, Object... params) {if (logger != null && logger.isDebugEnabled()) {logger.debug(getLogString(message, params));}}public static void info(Logger logger, String message) {info(logger, message, (Object[])null);}
public abstract class CollectBaseHandler<T> implements CollectService<T>, InitializingBean {private static final Logger logger = LoggerFactory.getLogger(FeatureCollectBaseHandler.class);}
public void dataSourceCollect(DecisionSessionContext sessionContext, FeatureContext featureContext) {try {LogUtil.info(logger, "”);} catch (HyxfException he){LogUtil.error(logger, "");}}
博文参考
《软件设计模式》
相关文章:

设计模式——Singleton(单例)设计模式
摘要 本文介绍了单例设计模式的概念、实现和应用场景。单例模式确保某个类只有一个实例,节省资源并提供全局访问点。文章详细解释了单例模式的实现要素,包括私有构造方法、静态实例和公共静态方法,并探讨了其在数据库连接池、日志记录器和配…...

深入理解 CSS 文本换行: overflow-wrap 和 word-break
前言 正常情况下,在固定宽度的盒子中的中文会自动换行。但是,当遇到非常长的英文单词或者很长的 URL 时,文本可能就不会自动换行,而会溢出所在容器。幸运的是,CSS 为我们提供了一些和文本换行相关的属性;今…...

Java-27 深入浅出 Spring - 实现简易Ioc-03 在上节的业务下手动实现IoC
点一下关注吧!!!非常感谢!!持续更新!!! 大数据篇正在更新!https://blog.csdn.net/w776341482/category_12713819.html 目前已经更新到了: MyBatisÿ…...

kubernetes学习-使用metrics-server监控集群资源和查看日志
kubernetes学习-使用metrics-server监控集群资源和查看日志 一 、简介二、应用场景三、部署四、查看日志 一 、简介 Metrics Server 是一个用于 Kubernetes 集群的监控工具,它用于收集、存储和提供关于集群中各种资源的度量数据。Metrics Server 是 Kubernetes 中一…...

解决 Git Permission denied 问题
前言 push项目时出现gitgithub.com: Permission denied (publickey). fatal: Could not read from remote repository.Please make sure you have the correct access rights and the repository exists.出现这个问题表示你在尝试将本地代码推送到GitHub时,没有提供…...

CCNP_SEC_ASA 第三天作业
实验需求: ASA 使用列表放行 Outside 路由器到 DMZ 路由器的 WWW 流量并拒绝 Telnet 流量,当放行和拒绝流量匹配后产生日志通告。 提示:需要使能 ASA的日志功能和 DMZ路由器的 HTTP功能。 设备配置: ##此处展示各设备的配置&am…...

TypeError: Cannot read properties of null (reading ‘ce‘)
vue项目本地跑不起来,但是build之后能运行,本地报错 是因为你的vue版本不对,你的package可能是这样写的 这个表示你允许你的npm安装vue3的任意版本,但是build是按照这个版本来的,所以build之后能运行,本地运…...
AdminJS - 集成 MySQL 的现代化管理面板开发指南
AdminJS - 集成 MySQL 的现代化管理面板开发指南 MySQL 集成配置 首先需要安装必要的依赖: npm install adminjs adminjs/express express npm install adminjs/sequelize sequelize mysql2基础配置示例 const AdminJS require(adminjs) const AdminJSExpress …...

上传文件(vue3)
使用el-upload 先上传到文件服务器,生成url 然后点击确定按钮: 保存数据 <template><el-dialog top"48px" width"500" title"新增协议" :modelValue"visible" close"handleClose()">…...

【Win10 环境vscode配置boost】
文章目录 Boost exe版本windows环境安装vscode配置安装测试总结 Boost exe版本windows环境安装 这里不介绍boost源码安装,请自行网络搜索。本文要介绍的是window下单c文件(cpp),调用boost库的执行配置。不涉及多文件。 安装文件下…...

中间件 redis安装
redis官网地址:Redis - The Real-time Data Platform 环境 CentOS Linux release 7.9.2009 (Core) java version "17.0.12" 2024-07-16 LTS 1、通过压缩包安装redis 1,远程下载redis压缩包,或去官网下载:Downloads …...
[java] 简单的熔断器scala语言案例
failureRateInterval时间内如果addEx(错误)达到 maxFailuresPerInterval 次数,则fused方法返回true,表示触发熔断,进入冷却期coolingInterval,冷却期内fused方法返回true,冷却期过后进入下一个错误统计周期。 scala语言完成 imp…...
【java】序列化的种类和使用场景
文章目录 序列化概述什么是序列化?序列化的作用 Java内置序列化java.io.Serializable接口使用ObjectOutputStream和ObjectInputStream优缺点分析 自定义序列化实现Externalizable接口自定义序列化方法适用场景 第三方序列化框架KryoProtobuf (Google Protocol Buffe…...
Qt5与Qt6中的高DPI缩放属性解析
在Qt5中,高DPI缩放默认是禁用的。为了启用它,开发者需要设置Qt::AA_EnableHighDpiScaling应用程序属性。然而,在Qt6中,高DPI缩放默认是启用的,并且不能被禁用。这种变化使得开发者在处理高分辨率屏幕时更加方便&#x…...
Mac使用总结
Mac 常用快捷键 复制:Cmdc粘贴:Cmdv只粘贴文档: ShiftCmdv行首: Cmd<行尾:Cmd>鼠标处选中到行首:ShiftCmd<鼠标处选中到行尾:ShiftCmd>选中整行:上面两个命令组合鼠标处…...

【日期规则】EXCEl 自定义日期匹配规则,学习基础知识,自由匹配场景
excel 新建规则工具路径:开始 - 条件格式 - 新建规则 B$1TODAY() 注意:新建规则后,要点击 条件格式 - 管理规则 - 应用于 要选择规则应用范围 使用场景: excel 做进度管理当中可以查看当天的情况;每周的学习规划 或…...
苹果电脑可以安装windows操作系统吗?Mac OS X/OS X/macOS傻傻分不清?macOS系统的Java支持?什么是macOS的五大API法王?
苹果电脑可以安装windows操作系统吗? 先抛开虚拟机安装,苹果电脑可以安装Windows操作系统。苹果公司提供了一个名为Boot Camp的软件,它允许用户在Mac电脑上安装Windows操作系统。通过Boot Camp,用户可以在启动电脑时选择是要进入macOS还是Wi…...

芋道SpringBoot配置Maven、创建SpringBoot项目、创建Web接口、读取配置信息
🌹作者主页:青花锁 🌹简介:Java领域优质创作者🏆、Java微服务架构公号作者😄 🌹简历模板、学习资料、面试题库、技术互助 🌹文末获取联系方式 📝 系列文章目录 第一章 芋…...

物理机内网穿透
前言: 本文主要讲述如何使用内网穿透以及其安全性。 将带领大家在公网上搭建几个常用靶场。 一,什么是内网穿透。 大多数情况下,我们的个人电脑都处于内网,即没有可公开访问的独立 IP 地址,因此其他内网用户找不到…...

Vue 3: 通过图片链接获取图片颜色,间接设置背景颜色
在现代Web开发中,动态获取和处理图像数据是一个常见的需求。例如,你可能希望自动提取一张图片的主色调,以便根据这些颜色进行UI主题调整或其他视觉效果的处理。本文将介绍如何在Vue 3项目中,通过一个图片链接获取图片的颜色信息。…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...

Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...