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

news2024/10/28 10:59:39

一、引言

        在软件工程中,软件开发,设计模式是提高代码复用性和可维护性的有效工具。单例模式(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 main

import "sync"

var instance *Singleton
var once sync.Once

type 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 = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
        return cls._instance
    
singleton1 = 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.coloradmin.cn/o/2225387.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

unity 导入的模型设置详谈

文章目录 1.Model 模型1.1 Scene:场景级属性,例如是否导入灯光和照相机,以及使用什么比例因子1.2 Mesh:网格的属性1.3 Generate :与几何相关的属性,用于处理拓扑,UV和法线 2.Rig 骨骼3.Animatio…

C语言小游戏3——扫雷

扫雷游戏 1. 扫雷游戏的功能说明 使用控制台实现经典的扫雷游戏游戏可以通过菜单实现继续玩或者退出游戏扫雷的棋盘是 9*9的格子默认随机布置 10个雷可以排查雷如果位置不是雷,就显示周围有几个雷如果位置是雷,就炸死游戏结束把除10个雷之外的所有雷都找…

C语言 | Leetcode C语言题解之第514题自由之路

题目&#xff1a; 题解&#xff1a; int findRotateSteps(char* ring, char* key) {int n strlen(ring), m strlen(key);int pos[26][n], posSize[26];memset(posSize, 0, sizeof(posSize));for (int i 0; i < n; i) {int x ring[i] - a;pos[x][posSize[x]] i;}int dp…

H3C vlan和trunk配置

vlan和trunk配置实验 实验拓扑图 实验需求 1.配置pc的IP地址 2.在sw1和sw2上分别创建vlan10和vlan20&#xff0c;要求pc3和pc5输入vlan10&#xff0c;pc4和pc6属于vlan20 3.sw1和sw2相连的接口配置为trunk类型&#xff0c;运行vlan10和vlan20通过 4.测试效果&#xff0c;同…

Springboot整合原生ES依赖

前言 Springboot整合依赖大概有三种方式&#xff1a; es原生依赖&#xff1a;elasticsearch-rest-high-level-clientSpring Data ElasticsearchEasy-es 三者的区别 1. Elasticsearch Rest High Level Client 简介: 这是官方提供的 Elasticsearch 客户端&#xff0c;支持…

大语言模型数据类型与环境安装(llama3模型)

文章目录 前言一、代码获取一、环境安装二、大语言模型数据类型1、基本文本指令数据类型2、数学指令数据类型3、几何图形指令数据类型4、多模态指令数据类型5、翻译指令数据类型三、vscode配置四、相关知识内容1、理解softmax内容2、torch相关函数nn.Embedding函数torch.nn.fun…

《手写Spring渐进式源码实践》实践笔记(第十一章 AOP-基于JDK、Cglib实现对象动态代理)

文章目录 第十一章 基于JDK、Cglib实现对象动态代理背景目标设计实现代码结构类图代理案例解析案例代码运行结果拆解案例 实现步骤 测试事先准备自定义拦截方法测试用例测试结果&#xff1a; 总结 第十一章 基于JDK、Cglib实现对象动态代理 背景 到本章节我们将要从 IOC 的实现…

Java版本的基于计算机视觉的跃动小子保卫主公自动通关计划之整体思路篇

系列文章 Java版本的基于计算机视觉的跃动小子保卫主公自动通关计划之图片分割篇 图片分类篇,执行计划生成篇,执行篇等后续篇章持续更新中,欢迎关注 文章目录 系列文章Java版本的基于计算机视觉的跃动小子保卫主公自动通关计划之整体思路篇构建二维数组构建消除时形态7个元素的…

【无标题】idea 一次性切换多个项目的分支

适合一个目录下面有多个子项目&#xff0c;维护着共同的分支 勾选Settings-Version Control->Git->Executor branch operations on all roots 勾选前&#xff08;是不能一次切换多个项目的分支为同一个分支的&#xff09; 勾选此选项 勾选后&#xff08;可以一次切换多个…

纯css实现瀑布流! 附源码!!!

瀑布流用于展示图片信息,我这里用的背景颜色来代替图片 PC端效果 源码(直接复制粘贴就可以运行了!!!) <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>PC端瀑布流</title><style>.box {w…

开发环境 —— Keil5 芯片包安装却找不到芯片

目 录 Keil 5添加芯片包一、查看芯片包名称二、下载芯片包三、安装芯片包四、安装成功却找不到芯片4.1 解压pack文件4.2 拷贝到指定路径 Keil 5添加芯片包 Keil只是一个开发平台&#xff0c;keil 5软件安装完成后&#xff0c;默认只能创建ARM芯片的工程。如果要创建其它芯片的…

网络编程_day3

#1024程序员节 #三次握手四次挥手#四次挥手#udp#recvfrom#sendto#服务器模型#客户端模型#Linux IO模型#阻塞式IO#非阻塞IO#设置非阻塞的方式 目录 【0】复习 【1】三次握手四次挥手 四次挥手 四次挥手既可以由客户端发起&#xff0c;也可以由服务器发起 【2】udp 1. 通信流程 2…

[OpenCV] 数字图像处理 C++ 学习——17轮廓发现详细讲解+附完整代码

文章目录 前言1.理论基础1.1轮廓发现1.2轮廓发现步骤1.3相关API(1)轮廓发现(find contour)(2)轮廓绘制(draw contour) 2.代码实现2.1图像预处理2.2轮廓发现2.3绘制轮廓2.4Trackbar 调整阈值 3.完整代码 前言 轮廓发现是图像处理中一个重要的操作&#xff0c;可以帮助找到图像中…

基于SSM+微信小程序的快递的管理系统(快递1)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 基于SSM微信小程序的快递管理平台&#xff0c;有管理员&#xff0c;用户&#xff0c;配送员&#xff0c; 1、管理员实现了个人中心&#xff0c;用户管理&#xff0c;配送员管理&#xff0…

IDM下载器 (Internet Download Manager) v6.42.2 中文免激活绿色版

Internet Download Manager (IDM下载器) 是一款先进的下载工具,可以提升您的下载速度高达5倍,支持续传&#xff0c;IDM可以让用户自动下载某些类型的文件&#xff0c;它可将文件划分为多个下载点以更快速度下载&#xff0c;并列出最近的下载&#xff0c;方便访问文件。相对于其…

如何通过sip信令以及抓包文件分析媒体发到哪个地方

前言 问题描述&#xff1a;A的媒体没转发到B&#xff0c;B只能听到回铃音&#xff0c;没有A的说话声音&#xff0c;并且fs这边按正常的信令发送了. 分析流程 分析早期媒体发送到哪一个IP 10.19.0.1发送了一个请求给10.19.0.157这个IP&#xff0c;然而这里的SDP媒体地址&am…

Leetcode 二叉树的右视图

好的&#xff0c;我来用中文详细解释这段代码的算法思想。 问题描述 题目要求给定一个二叉树的根节点&#xff0c;从树的右侧看过去&#xff0c;按从上到下的顺序返回看到的节点值。即&#xff0c;我们需要找到每一层的最右侧节点并将其加入结果中。 算法思想 这道题可以通…

【gRPC】什么是RPC——介绍一下RPC

说起RPC&#xff0c;博主使用CPP手搓了一个RPC项目&#xff0c;RPC简单来说&#xff0c;就是远程过程调用&#xff1a;我们一般在本地传入数据进行执行函数&#xff0c;然后返回一个结果&#xff1b;当我们使用RPC之后&#xff0c;我们可以将函数的执行过程放到另外一个服务器上…

go语言中的Scanf()输入函数

Scanf() 第一种情况 package mainimport "fmt"func main() {var a intfor {fmt.Println("请输入一个整数:")fmt.Scanf("%d", &a)fmt.Println("----------------", a)} }运行结果&#xff1a; 解释&#xff1a; 出现这种现象是因…

Docker下载途径

Docker不是Linux自带的&#xff0c;需要我们自己安装 官网&#xff1a;https://www.docker.com/ 安装步骤&#xff1a;https://docs.docker.com/engine/install/centos/ Docker Hub官网(镜像仓库)&#xff1a;https://hub.docker.com/ 在线安装docker 先卸载旧的docker s…