设计模式——单例模式(创建型)

引言

单例模式是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。

问题

单例模式同时解决了两个问题, 所以违反了单一职责原则

  1. 保证一个类只有一个实例。 为什么会有人想要控制一个类所拥有的实例数量? 最常见的原因是控制某些共享资源 (例如数据库或文件) 的访问权限。

    它的运作方式是这样的: 如果你创建了一个对象, 同时过一会儿后你决定再创建一个新对象, 此时你会获得之前已创建的对象, 而不是一个新对象。

    注意, 普通构造函数无法实现上述行为, 因为构造函数的设计决定了它必须总是返回一个新对象。

 

 2. 为该实例提供一个全局访问节点。 还记得你 (好吧, 其实是我自己) 用过的那些存储重要对象的全局变量吗? 它们在使用上十分方便, 但同时也非常不安全, 因为任何代码都有可能覆盖掉那些变量的内容, 从而引发程序崩溃。

和全局变量一样, 单例模式也允许在程序的任何地方访问特定对象。 但是它可以保护该实例不被其他代码覆盖。

还有一点: 你不会希望解决同一个问题的代码分散在程序各处的。 因此更好的方式是将其放在同一个类中, 特别是当其他代码已经依赖这个类时更应该如此。

如今, 单例模式已经变得非常流行, 以至于人们会将只解决上文描述中任意一个问题的东西称为单例

解决方案

所有单例的实现都包含以下两个相同的步骤:

  • 将默认构造函数设为私有, 防止其他对象使用单例类的 new运算符。
  • 新建一个静态构建方法作为构造函数。 该函数会 “偷偷” 调用私有构造函数来创建对象, 并将其保存在一个静态成员变量中。 此后所有对于该函数的调用都将返回这一缓存对象。

如果你的代码能够访问单例类, 那它就能调用单例类的静态方法。 无论何时调用该方法, 它总是会返回相同的对象。

真实世界类比

政府是单例模式的一个很好的示例。 一个国家只有一个官方政府。 不管组成政府的每个人的身份是什么, ​ “某政府” 这一称谓总是鉴别那些掌权者的全局访问节点。

单例模式结构

伪代码

在本例中, 数据库连接类即是一个单例。 该类不提供公有构造函数, 因此获取该对象的唯一方式是调用 获取实例方法。 该方法将缓存首次生成的对象, 并为所有后续调用返回该对象。

 

// 数据库类会对`getInstance(获取实例)`方法进行定义以让客户端在程序各处
// 都能访问相同的数据库连接实例。
class Database is
    // 保存单例实例的成员变量必须被声明为静态类型。
    private static field instance: Database

    // 单例的构造函数必须永远是私有类型,以防止使用`new`运算符直接调用构
    // 造方法。
    private constructor Database() is
        // 部分初始化代码(例如到数据库服务器的实际连接)。
        // ……

    // 用于控制对单例实例的访问权限的静态方法。
    public static method getInstance() is
        if (Database.instance == null) then
            acquireThreadLock() and then
                // 确保在该线程等待解锁时,其他线程没有初始化该实例。
                if (Database.instance == null) then
                    Database.instance = new Database()
        return Database.instance

    // 最后,任何单例都必须定义一些可在其实例上执行的业务逻辑。
    public method query(sql) is
        // 比如应用的所有数据库查询请求都需要通过该方法进行。因此,你可以
        // 在这里添加限流或缓冲逻辑。
        // ……

class Application is
    method main() is
        Database foo = Database.getInstance()
        foo.query("SELECT ……")
        // ……
        Database bar = Database.getInstance()
        bar.query("SELECT ……")
        // 变量 `bar` 和 `foo` 中将包含同一个对象。

单例模式适合应用场景

 如果程序中的某个类对于所有客户端只有一个可用的实例, 可以使用单例模式。

 单例模式禁止通过除特殊构建方法以外的任何方式来创建自身类的对象。 该方法可以创建一个新对象, 但如果该对象已经被创建, 则返回已有的对象。

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

 单例模式与全局变量不同, 它保证类只存在一个实例。 除了单例类自己以外, 无法通过任何方式替换缓存的实例。

请注意, 你可以随时调整限制并设定生成单例实例的数量, 只需修改 获取实例方法, 即 getInstance 中的代码即可实现。

实现方式

  1. 在类中添加一个私有静态成员变量用于保存单例实例。

  2. 声明一个公有静态构建方法用于获取单例实例。

  3. 在静态方法中实现"延迟初始化"。 该方法会在首次被调用时创建一个新对象, 并将其存储在静态成员变量中。 此后该方法每次被调用时都返回该实例。

  4. 将类的构造函数设为私有。 类的静态方法仍能调用构造函数, 但是其他对象不能调用。

  5. 检查客户端代码, 将对单例的构造函数的调用替换为对其静态构建方法的调用。

单例模式优缺点

  •  你可以保证一个类只有一个实例。
  •  你获得了一个指向该实例的全局访问节点。
  •  仅在首次请求单例对象时对其进行初始化。
  •  违反了单一职责原则。 该模式同时解决了两个问题。
  •  单例模式可能掩盖不良设计, 比如程序各组件之间相互了解过多等。
  •  该模式在多线程环境下需要进行特殊处理, 避免多个线程多次创建单例对象。
  •  单例的客户端代码单元测试可能会比较困难, 因为许多测试框架以基于继承的方式创建模拟对象。 由于单例类的构造函数是私有的, 而且绝大部分语言无法重写静态方法, 所以你需要想出仔细考虑模拟单例的方法。 要么干脆不编写测试代码, 或者不使用单例模式。

与其他模式的关系

  • 外观模式类通常可以转换为单例模式类, 因为在大部分情况下一个外观对象就足够了。

  • 如果你能将对象的所有共享状态简化为一个享元对象, 那么享元模式就和单利例类似了。 但这两个模式有两个根本性的不同。

    1. 只会有一个单例实体, 但是享元类可以有多个实体, 各实体的内在状态也可以不同。
    2. 单例对象可以是可变的。 享元对象是不可变的。
  • 抽象工厂模式、 生成器模式和原型模式都可以用单例来实现。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/242579.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

回归预测 | MATLAB实现CHOA-BiLSTM黑猩猩优化算法优化双向长短期记忆网络回归预测 (多指标,多图)

回归预测 | MATLAB实现CHOA-BiLSTM黑猩猩优化算法优化双向长短期记忆网络回归预测 (多指标,多图) 目录 回归预测 | MATLAB实现CHOA-BiLSTM黑猩猩优化算法优化双向长短期记忆网络回归预测 (多指标,多图)效果…

YOLOv8改进 | 2023主干篇 | EfficientViT替换Backbone(高效的视觉变换网络)

一、本文介绍 本文给大家带来的改进机制是EfficientViT(高效的视觉变换网络),EfficientViT的核心是一种轻量级的多尺度线性注意力模块,能够在只使用硬件高效操作的情况下实现全局感受野和多尺度学习。本文带来是2023年的最新版本…

是谁,在参与数十亿美元的量子市场?

量子技术是最不为人们所了解、但却最有希望在未来几年颠覆商业和产业的进步技术之一。 很少有像量子信息科学市场这样小的市场能引起如此热烈的讨论。上周,根据Hyperion Research在圣克拉拉举行的Q2B硅谷会议上发布的年度量子计算(QC)市场更新…

【开源软件】最好的开源软件-2023-第23名 Apache Druid

自我介绍 做一个简单介绍,酒架年近48 ,有20多年IT工作经历,目前在一家500强做企业架构.因为工作需要,另外也因为兴趣涉猎比较广,为了自己学习建立了三个博客,分别是【全球IT瞭望】,【…

Git使用——IDEA中git branch显示乱码 后面提示standard input 如何解决

问题描述: idea中的terminal中输入git branch显示乱码 解决方案 在idea的file里面,进行设置 选择安装的git下面的bash 参考博客: https://blog.csdn.net/weixin_39925939/article/details/122410453

使用 Timm 库替换 YOLOv8 主干网络 | 1000+ 主干融合YOLOv8

文章目录 前言版本差异说明替换方法parse_moedl( ) 方法_predict_once( ) 方法修改 yaml ,加载主干论文引用timm 是一个包含最先进计算机视觉模型、层、工具、优化器、调度器、数据加载器、数据增强和训练/评估脚本的库。 该库内置了 700 多个预训练模型,并且设计灵活易用。…

算法基础之树的重心

树的重心 无向图: 边没有方向 有向图:边有方向 只能单向询问 无向图建立双向的边 要求输出每种情况连通块个数最大值的最小值**(最小的最大值)** #include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace s…

开发案例:使用canvas实现图表系列之折线图

一、功能结构 实现一个公共组件的时候&#xff0c;首先分析一下大概的实现结构以及开发思路&#xff0c;方便我们少走弯路&#xff0c;也可以使组件更加容易拓展&#xff0c;维护性更强。然后我会把功能逐个拆开来讲&#xff0c;这样大家才能学习到更详细的内容。下面简单阐述…

一个Redis实例最多能存放多少keys

程序员的公众号&#xff1a;源1024&#xff0c;获取更多资料&#xff0c;无加密无套路&#xff01; 最近整理了一份大厂面试资料《史上最全大厂面试题》&#xff0c;Springboot、微服务、算法、数据结构、Zookeeper、Mybatis、Dubbo、linux、Kafka、Elasticsearch、数据库等等 …

【Qt QML入门】Image

Image类型显示一个图像。 使用source属性将图像的源指定为URL。图像可以以Qt支持的任何标准图像格式提供&#xff0c;包括位图格式&#xff0c;如PNG和JPEG&#xff0c;以及矢量图形格式&#xff0c;如SVG。 如果没有指定宽度和高度属性&#xff0c;图像将自动使用加载图像的大…

如果我忽然嗝屁了,家人怎么继承我的财产

前言 笔者很喜欢的电影《寻梦环游记》有这么一句经典台词&#xff1a;“真正的死亡是世界上没有一个人记得你”。 然而&#xff0c;现实中我们所说的“死亡”&#xff0c;其实就是 他再不能与这个世界、与自己在乎的人有新的互动了。 本文&#xff0c;笔者想写一写 关于死亡的…

iOS16.5 以上12小时制/24小时制 HH/hh引起的时间计算错误

iOS16.5以上的版本&#xff0c;如果用yyy-MM-dd HH:mm:ss转换时间&#xff0c;则有肯能发生错误。 先上代码&#xff1a; NSString * timeStr "2023-01-01 11:13:32"; NSDateFormatter * dateFormatter [[NSDateFormatter alloc] init]; [dateFormatter setDateFo…

windows10下jdk安装

文章目录 windows10下jdk安装说明what安装包下载执行安装包验证是否安装成功 windows10下jdk安装 说明 操作系统&#xff1a;windows10 版本&#xff1a;1.8 what JDK(Java Development Kit) 是 Java 语言的软件开发工具包 安装包下载 https://www.oracle.com/java/techn…

Proxmox服务安装

文章目录 系统盘制作 TODO安装系统安装Proxmox系统安装wpa服务配置wifi通过IP访问Proxmox创建服务器配置服务器网络连接虚拟机方式第一种方法&#xff1a;通过建设OpenVPN方式连接虚拟机第二种方法&#xff1a;通过端口转发直连虚拟机设置安装ubuntu服务器允许root用户远程登录…

.net core提示The xx field is required,One or more validation errors occurred

访问接口时缺少model中的参数时&#xff0c;会提示&#xff1a; The xx field is required One or more validation errors occurred原因是.net core webapi默认参数为不可空&#xff0c;因此会验证并报错。 解决方案&#xff1a; 在项目的.csproj中&#xff0c;修改Nullable…

Android--Jetpack--数据库Room详解二

本是青灯不归客&#xff0c;却因浊酒恋红尘 一&#xff0c;基本使用 关于Room数据库的基本使用&#xff0c;请参考文章Android--Jetpack--数据库Room详解一-CSDN博客 二&#xff0c;Room与ViewModle,LiveData的结合使用 LiveData与ViewModle的使用&#xff0c;请参考文章Andr…

谷歌上架应用的机审流程或审核机制是怎么样的?

Google play是全球最大安卓应用市场&#xff0c;拥有巨大的流量&#xff0c;是开发者们上架应用的首选平台。不过&#xff0c;开发者们的应用需要经过谷歌严格审核&#xff0c;确保符合谷歌应用相关政策和法律法规才能成功上架。 众所周知&#xff0c;谷歌审核系统&#xff0c…

基于ssm民宿管理系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本民宿管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息&am…

c语言结构体调用格式与对齐

1.声明形式&#xff1a; struct 结构体名字 { 结构体成员 }结构体变量名&#xff1b; 2.赋值方法 3.结构体对齐&#xff1a; 1.起始偏移量&#xff1a;默认结构体第一个元素对齐0起始偏移量&#xff0c;第一个元素占一个字节&#xff0c;此时偏移量为1. 2.标准数&#xff…

基于stm32 FP-AUD-SMARTMIC1 音频系统开发

基于stm32 FP-AUD-SMARTMIC1 音频系统开发 是否需要申请加入数字音频系统研究开发交流答疑群(课题组)?可加我微信hezkz17, 本群提供音频技术答疑服务,+群赠送语音信号处理降噪算法,蓝牙耳机音频,DSP音频项目核心开发资料, FP-AUD-SMARTMIC1 是一个用于 STM32F4Discovery …