创建型模式-单例模式:定义、实现及应用

目录

  • 一、模式定义
  • 二、针对问题
    • 1.解决的问题
    • 2.解决方案
    • 3.举个例子
    • 4.设计模式适合场景
    • 5.实现方式
    • 6.优缺点
    • 7.与其他模式的关系
  • 三、代码实现

一、模式定义

单例模式(Singleton Pattern)是一种创建型模式,用于限制某个类只能创建一个对象。它提供了一个全局的静态方法,返回该类的唯一实例。如果实例不存在,该方法会创建一个新的实例;如果实例已经存在,则返回该实例。这样可以确保系统中的某个类只有一个实例,避免了不必要的资源消耗和重复操作。

二、针对问题

1.解决的问题

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

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

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

注意, 普通构造函数无法实现上述行为, 因为构造函数的设计决定了它必须总是返回一个新对象。
在这里插入图片描述
为该实例提供一个全局访问节点。 还记得你 (好吧, 其实是我自己) 用过的那些存储重要对象的全局变量吗? 它们在使用上十分方便, 但同时也非常不安全, 因为任何代码都有可能覆盖掉那些变量的内容, 从而引发程序崩溃。

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

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

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

2.解决方案

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

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

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

3.举个例子

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

4.设计模式适合场景

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

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

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

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

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

5.实现方式

  1. 在类中添加一个私有静态成员变量用于保存单例实例。
  2. 声明一个公有静态构建方法用于获取单例实例。
  3. 在静态方法中实现"延迟初始化"。 该方法会在首次被调用时创建一个新对象, 并将其存储在静态成员变量中。 此后该方法每次被调用时都返回该实例。
  4. 将类的构造函数设为私有。 类的静态方法仍能调用构造函数, 但是其他对象不能调用。
  5. 检查客户端代码, 将对单例的构造函数的调用替换为对其静态构建方法的调用。

6.优缺点

优点:

  1. 你可以保证一个类只有一个实例
  2. 你获得了一个指向该实例的全局访问节点
  3. 仅在首次请求单例对象时对其进行初始化

缺点:

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

7.与其他模式的关系

  1. 外观模式类通常可以转换为单例模式类, 因为在大部分情况下一个外观对象就足够了。
  2. 如果你能将对象的所有共享状态简化为一个享元对象, 那么享元模式就和单例类似了。 但这两个模式有两个根本性的不同:
    1.1. 只会有一个单例实体, 但是享元类可以有多个实体, 各实体的内在状态也可以不同
    1.2. 单例对象可以是可变的。 享元对象是不可变的
  3. 抽象工厂模式生成器模式原型模式都可以用单例来实现

三、代码实现

/*** 单例模式demo*/
public class Singleton {private static Singleton instance;public String value;private Singleton(String value) {this.value = value;}public static Singleton getInstance(String value) {if (instance == null) {instance = new Singleton(value);}return instance;}public static void main(String[] args) {System.out.println("如果您看到相同的值,则singleton被重用(耶!)" + "\n" +"如果您看到不同的值,则会创建2个singleton(booo!!)" + "\n\n" +"RESULT:" + "\n");Singleton singleton = Singleton.getInstance("FOO");Singleton anotherSingleton = Singleton.getInstance("BAR");System.out.println(singleton.value);System.out.println(anotherSingleton.value);}}

输出结果:
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数仓建模维度建模理论知识

0. 思维导图 第 1 章 数据仓库概述 1.1 数据仓库概述 数据仓库是一个为数据分析而设计的企业级数据管理系统。数据仓库可集中、整合多个信息源的大量数据,借助数据仓库的分析能力,企业可从数据中获得宝贵的信息进而改进决策。同时,随着时间的…

压力测试工具-Jmeter使用总结

目录 一.前言 二.线程组 三.线程组的组件 四.线程组-HTTP请求 1、JSON提取器 2、XPATH提取器 3、正则表达式提取器 五.线程组-断言 1、响应断言 2、JSON断言 六.创建测试 1.创建线程组 2.配置元件 3.构造HTTP请求 4.添加HTTP请求头 5.添加断言 6.添加查看结果树…

数仓治理-存储资源治理

目录 一、存储资源治理的背景 二、存储资源治理的流程及思路 三、治理前如何评估 3.1 无用数据表/临时数据表下线评估 3.2 表及分区的生命周期评估 3.3 存储及压缩格式评估 3.4 根据业务场景实现节省存储评估 四、治理后的成效如何评估 一、存储资源治理的背景 由于早…

人工智能深度学习发展历程-纪年录

前言 为了理解模型之间的改进关系、明确深度学习的发展目标、提高自身对模型的深度理解、贯彻爱与和平的理念。总之,我做了如下表格。 时间 重大突破 模型改进 详细信息 1847 SGD 随机梯度下降 1995 SVM 支持向量机 1982 RNN 循环神经网络,…

[晓理紫]每日论文分享(有中文摘要,源码或项目地址)--大模型、扩散模型、视觉

专属领域论文订阅 关注{晓理紫|小李子},每日更新论文,如感兴趣,请转发给有需要的同学,谢谢支持 如果你感觉对你有所帮助,请关注我,每日准时为你推送最新论文。 为了答谢各位网友的支持,从今日起…

springboot在线问诊系统-计算机毕业设计源码00211

摘 要 针对医院门诊等问题,对在线问诊进行研究分析,然后开发设计出在线问诊系统以解决问题。在线问诊系统主要功能模块包括首页、轮播图管理、公告信息管理、资源管理、系统用户管理(管理员、患者用户、医生用户)、模块管理&#…

Vue 环境准备

1.安装vscode https://code.visualstudio.com/ 2.安装开发vue所需插件: Vetur —— 语法高亮、智能感知、Emmet等 包含格式化功能, AltShiftF (格式化全文),CtrlK CtrlF(格式化选中 代码,两…

[C语言] 指针详解(1)

一. 指针 利用指针,可以找到相对应内存地址(唯一的一段编号),从而定位数据. (通俗来说,指针就是变量,用来存放内存单元的地址) 保存一段 16进制的 地址编号 二、指针类型/变量: 类型: 基础类型* 如: int* char*指针变量: int* pa pa就为指针变…

Shopee越南本土店好做吗?越南本土Shopee店家如何收款?站斧浏览器

Shopee越南本土店好做吗? 对于越南本土的Shopee店家来说,他们可能会关心Shopee平台的运营情况和是否适合他们开展电商业务。那么,Shopee好做吗?以下是一些相关的讨论点。 用户基础和市场规模 作为东南亚地区最大的电商平台之一…

WPA3,WPA2,WPA的核心要点

目录 WPA是什么? WPA:WiFi protected Access 安全是什么? 安全 认证加密 IEEE 802.11定义了2个阶段:pre-RSNA, RSNA Pre-RSNA: RSNA:robust security network association RSNA Authent…

记录关于node接收上传文件formData踩的坑

1.vue2使用插件formidable实现接收文件,首先接口不可以使用任何中间件,否则form.parse()方法不执行。 const express require(express) const multipart require(connect-multiparty); const testController require(../controller/testController)/…

webpack源码分析——truncateArgs函数

一、truncateArgs 函数 函数功能 该函数可以用于用户界面中的文本截断,确保长文本在有限的显示空间内能够适当显示,并且用户可以了解到部分文本已被省略。 函数参数 args:参数数组。用于输出到界面上maxLength:当前界面上可容纳…