【再谈设计模式】单例模式~唯一性的守护者

一、引言

        在软件工程中,软件开发,设计模式是提高代码复用性和可维护性的有效工具。单例模式(Singleton Pattern)作为一种创建型设计模式,旨在确保一个类只有一个实例,并提供对该实例的全局访问。这一模式在许多场景中都显得尤为重要,尤其是在需要共享资源或协调系统状态时。

二、定义与描述

        单例模式的核心思想是限制一个类仅能实例化一次,并提供一个全局访问点。这样可以避免重复实例化导致的资源浪费和状态不一致的问题。

结构

单例模式通常包含以下几个组成部分:

  • 私有构造函数:防止外部类直接实例化。
  • 一个静态变量:持有唯一的实例。
  • 一个静态方法:用于获取该实例。

三、抽象背景

        单例模式的背景可以追溯到多个设计需求的实际应用。例如,当一个应用程序需要使用一个共享的配置文件、数据库连接或共享资源时,单例模式便成为一个很好的选择。在这种情况下,程序不能允许多个实例同时存在,以免造成数据污染和不一致。

四、适用场景与现实问题解决

单例模式常用于以下场景:

  • 配置管理:在整个应用中共享配置文件或参数。
  • 日志管理:全局共享的日志记录器。
  • 数据库连接池:管理数据库连接的共享实例。

  • 线程池管理:确保线程池在整个应用中只有一个实例。

       通过应用单例模式,可以有效避免各类资源的误用和浪费,从而提升程序的性能和稳定性。旨在确保一个类只有一个实例,并提供一个全局访问点。为了让这个概念更易于理解,我们可以使用一个生活中的实际问题来说明。

生活例子:办公室的打印机

        在一个办公室工作,办公室里有一台打印机。现在我们来看看这台打印机在使用中的几种情况:

        唯一性:这个办公室只能有一台打印机。想象一下,如果有多台打印机,可能会导致很多问题,比如文件打印到错误的打印机、打印任务混乱等。因此,我们需要确保只有一台打印机。

        共享访问:办公室里的每个人都需要使用这台打印机,无论是打印文件还是复印资料。因此,我们需要一个简单的方法让每个人都能访问这台打印机,而不需要每次都去找。

        节省资源:维护多台打印机的成本和管理会耗费大量时间和精力。只有一台打印机可以集中管理,更加高效。

单例模式的类比

        在编程中,单例模式就像这台办公室的打印机一样。它确保一个类(例如打印机类)只有一个实例,并提供一个全局的访问点。在代码中实现单例模式通常涉及以下几个步骤:

  • 私有构造函数:防止其他地方直接创建新实例。
  • 静态变量:用于保存唯一的实例。
  • 公共静态方法:提供访问该实例的方式。

        通过这种方式,代码中需要使用打印机的地方,都会获取到同一个实例,避免了实例重复,确保了全局统一性。

        单例模式就像是确保办公室只有一台打印机,避免了资源的浪费和管理的复杂性,让每个人都可以方便地访问这台打印机。而在实际编程中,单例模式则确保了一个类的唯一性和资源的高效利用。

五、初衷与问题解决

        单例模式的初衷是为了控制对象的数量,使其不被无意创建。许多开发者面临对象管理不当导致的资源浪费和状态不一致的问题,而这一模式恰好能够有效解决这些问题。单例模式实现了对全局资源的集中管理,提高了系统的可维护性和安全性。

六、各语言实现与编码示例

Java 实现

public class Singleton {private static Singleton instance;private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}

Go 实现

package mainimport "sync"var instance *Singleton
var once sync.Oncetype Singleton struct{}func GetInstance() *Singleton {once.Do(func() {instance = &Singleton{}})return instance
}

C++ 实现

class Singleton {
private:static Singleton* instance;Singleton() {}
public:static Singleton* getInstance() {if (instance == nullptr) {instance = new Singleton();}return instance;}
};Singleton* Singleton::instance = nullptr;

Python 实现

class Singleton:_instance = Nonedef __new__(cls, *args, **kwargs):if not cls._instance:cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)return cls._instancesingleton1 = Singleton()
singleton2 = Singleton()assert singleton1 is singleton2  # True

七、单例模式的优缺点

优点

  • 节省内存:同一时刻只存在一个实例。
  • 全局访问:提供全局访问点,方便在程序的不同部分共享资源。
  • 控制资源使用:通过限制实例化次数,可以避免资源浪费。

缺点

  • 可扩展性差:在某些场景下可能会导致系统中的“单点故障”。
  • 更难测试:单例模式可能使得测试变得复杂,因为它引入了全局状态。
  • 潜在的线程安全问题:在多线程环境中需谨慎处理,可能需要额外的同步机制。

八、单例模式的升级版

        在实际应用中,单例模式可能会演变成更复杂的形式,包括饿汉单例和懒汉单例。

饿汉单例

        饿汉单例在类被加载时就创建实例,因此实例的创建是提前的。通常使用一个静态常量来存储单例的实例。

特点

  • 线程安全:实例在类加载时就创建,因此不需要额外的同步机制。
  • 容易实现:比较简单,没有复杂的逻辑。
  • 资源浪费:即使没有使用,也会在加载时就创建实例,这可能导致资源浪费。

示例代码

public class HungrySingleton {// 在静态变量中创建唯一的实例private static final HungrySingleton INSTANCE = new HungrySingleton();// 私有构造函数,防止外部创建对象private HungrySingleton() {}// 提供一个全局访问点public static HungrySingleton getInstance() {return INSTANCE;}
}

懒汉单例

        懒汉单例在第一次被调用时才会创建实例,因此实例的创建是延迟的。通常会使用一个私有静态变量来存储实例,并在访问时检查是否已经被创建。

特点

  • 延迟加载:只有在需要的时候才创建实例,如果不需要,则不会创建。
  • 线程不安全:如果多个线程同时访问 getInstance() 方法,可能会导致创建多个实例。为了解决这个问题,常常在方法上添加同步机制。
  • 实现复杂:需要考虑多线程访问的安全性和性能。

示例代码(线程不安全):

public class LazySingleton {private static LazySingleton instance;private LazySingleton() {}public static LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}
}

示例代码(线程安全,使用同步):

public class ThreadSafeLazySingleton {private static ThreadSafeLazySingleton instance;private ThreadSafeLazySingleton() {}public static synchronized ThreadSafeLazySingleton getInstance() {if (instance == null) {instance = new ThreadSafeLazySingleton();}return instance;}
}
  • 饿汉单例适合于实例创建比较简单,并且应用程序总是需要这个实例的情况。
  • 懒汉单例适合于实例创建开销比较大,或者在特定条件下才需要创建的情况,但需要注意线程安全的问题。

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

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

相关文章

UDP-鼠李糖合成酶基因的克隆与鉴定-文献精读76

何首乌中UDP-鼠李糖合成酶基因FmRHM1/2的克隆与鉴定 摘要 UDP-鼠李糖是一种由UDP-鼠李糖合酶(RHM)催化合成的鼠李糖供体,而鼠李糖是鼠李糖苷化合物的重要组成部分,植物中只有少数基因编码的酶参与UDP-鼠李糖生物合成。本研究基于…

创建多维数组的全部元素的索引np.indices

【小白从小学Python、C、Java】 【考研初试复试毕业设计】 【Python基础AI数据分析】 创建多维数组的 全部元素的索引 np.indices [太阳]选择题 根据题目代码,执行的结果是? import numpy as np arr np.arange(6).reshape((2, 3)) print(&quo…

C/C++ 矩阵的QR分解

#include <iostream> #include <vector> using namespace std;int main() /* 矩阵A的QR分解*/ {// 动态分配内存int m 3; // 行数int n 3; // 列数// 初始化矩阵Adouble A[3][3] {{1, 2, 2},{2, 1, 2},{1, 2, 1}};double R[3][3] { 0 };double Q[3][3] { 0 };…

2023-2024年教育教学改革、教学成果奖等项目申请书合集-最新出炉 附下载链接

2023-2024年教育教学改革、教学成果奖等项目申请书合集 下载链接-点它&#x1f449;&#x1f449;&#x1f449;&#xff1a;2023-2024年教育教学改革、教学成果奖等项目申请书合集-最新出炉.zip 资源介绍 本资源展示了2023-2024年高等教育领域的教育教学改革项目以及教学成…

某大型建设集团有限公司信息化技术方案(250页WORD)

方案介绍&#xff1a; 本信息化技术方案旨在构建一个集成度高、功能全面、操作简便的信息化系统&#xff0c;涵盖公司管理、业务运营、项目监控、数据分析等多个方面。通过引入云计算、大数据、物联网、人工智能等先进技术&#xff0c;实现资源的优化配置、流程的高效协同和数…

EDA --软件开发之路

之前一直在一家做数据处理的公司&#xff0c;从事c开发&#xff0c;公司业务稳定&#xff0c;项目有忙有闲&#xff0c;时而看下c&#xff0c;数据库&#xff0c;linux相关书籍&#xff0c;后面跳槽到了家eda公司&#xff0c;开始了一段eda开发之路。 eda 是 electric design …

Failed to install Visual Studio Code update

当关闭vsCode的时候&#xff0c;出现了下面的报错&#xff1a; 可能是之前将vscode文件换了位置导致的&#xff0c;并且vscode在桌面的图标也变成了下面这个&#xff1a; 解决方法&#xff1a; 找到上图路径的log文件并打开&#xff1a; 搜索电脑中的Code.exe文件 并粘贴到上…

神经网络进行波士顿房价预测

前言 前一阵学校有五一数模节校赛&#xff0c;和朋友一起参加做B题&#xff0c;波士顿房价预测&#xff0c;算是第一次自己动手实现一个简单的小网络吧&#xff0c;虽然很简单&#xff0c;但还是想记录一下。 题目介绍 波士顿住房数据由哈里森和鲁宾菲尔德于1978年Harrison …

如果要用示波器测量电路中某处电压与电流的相位差,应如何实现?

使用示波器测量电路中某处电压与电流的相位差&#xff0c;可以通过以下步骤实现&#xff1a; 1. 准备和连接 所需设备 示波器&#xff08;双通道&#xff09;电流探头&#xff08;或电阻分压器用于间接测量电流&#xff09;电压探头 连接探头到待测信号 电压探头&#xff…

恋爱脑学Rust之闭包三Traits:Fn,FnOnce,FnMut

在Rust中&#xff0c;FnOnce、FnMut和Fn是三个用于表示闭包&#xff08;closure&#xff09;类型的trait。闭包是一种特殊的函数&#xff0c;它可以捕获其环境变量&#xff0c;即在其定义时所处的作用域中的变量。以下是关于这三个trait的详细介绍&#xff1a; 1. FnOnce&#…

【Linux:TCP通信流程】

网络字节序&#xff1a; 计算机中存在两种存储字节的方式&#xff0c;分别是&#xff1a;大端存储和小端存储&#xff0c;TCP/IP协议规定&#xff0c;网络数据字节流应采用大端字节序。如果当前发送的主机是小端机就需要将数据转化为大端&#xff0c;再发送。 小端存储&#…

HTB:Cicada[WriteUP]

目录 连接至HTB服务器并启动靶机 使用nmap对靶机进行开放端口扫描 使用nmap对靶机开放端口进行脚本、服务信息扫描 首先尝试空密码连接靶机SMB服务 由于不知道账户名&#xff0c;这里我们使用crackmapexec对smb服务进行用户爆破 通过该账户连接至靶机SMB服务器提取敏感信…

17. 云计算和分布式计算

文章目录 第17章 云计算和分布式计算17.1 云基础17.2 云中的故障超时长尾延迟 17.3 利用多个实例提升性能和可用性分布式计算和负载均衡器分布式系统中的状态管理分布式系统中的时间协调分布式系统中的数据协调自动扩展&#xff1a;实例的自动创建和销毁自动扩展虚拟机自动缩放…

【GESP】C++一级知识点研究,cout和printf性能差异分析

一道简单循环输出练习题(BCQM3148&#xff0c;循环输出)&#xff0c;由于cout的代码超时问题&#xff0c;让我注意到二者在使用上的差异&#xff0c;遂查阅研究如下。 全文详见&#xff1a;https://www.coderli.com/gesp-knowledge-cout-printf/【GESP】C一级知识点研究&#…

入门 | Kafka数据使用vector消费到Loki中使用grafana展示

一、Loki的基本介绍 1、基本介绍 Loki 是由 Grafana Labs 开发的一款水平可扩展、高性价比的日志聚合系统。它的设计初衷是为了有效地处理和存储大量的日志数据&#xff0c;与 Grafana 生态系统紧密集成&#xff0c;方便用户在 Grafana 中对日志进行查询和可视化操作。 从架构…

Golang | Leetcode Golang题解之第515题在每个树行中找最大值

题目&#xff1a; 题解&#xff1a; func largestValues(root *TreeNode) (ans []int) {if root nil {return}q : []*TreeNode{root}for len(q) > 0 {maxVal : math.MinInt32tmp : qq nilfor _, node : range tmp {maxVal max(maxVal, node.Val)if node.Left ! nil {q …

Vue3的router和Vuex的学习笔记整理

一、路由的基本搭建 1、安装 npm install vue-router --registryhttps://registry.npmmirror.com 2、配置路由模块 第一步&#xff1a;src/router/index.js创建文件 第二步&#xff1a;在src/view下面创建两个vue文件&#xff0c;一个叫Home.vue和About.vue 第三步&#x…

vue插件清除 所有console.log()

一、作用 1、提升性能console.log() 语句会消耗一定的性能&#xff0c;尤其是在频繁调用的情况下。在生产环境中移除这些语句可以提高应用的运行效率。 2、减少信息泄露console.log() 可以输出敏感信息&#xff08;如用户数据、API 响应等&#xff09;。在生产环境中&#xf…

vue项目中如何在路由变化时增加一个进度条

在 Vue.js 项目中&#xff0c;使用路由&#xff08;如 Vue Router&#xff09;时&#xff0c;为了提升用户体验&#xff0c;你可能会想要在路由变化时显示一个进度条。这可以通过多种方式实现&#xff0c;其中一种流行的做法是使用第三方库&#xff0c;如 vue-loading-bar 或 n…

python 模块和包、类和对象

模块 模块是包含 Python 代码的文件&#xff0c;通常用于组织相关的函数、类和其他语句。模块可以被导入并在其他 Python 文件中使用。 创建模块 假设你创建了一个名为 mymodule.py 的文件&#xff0c;内容如下&#xff1a; # mymodule.pydef greet(name): return f"…