单例模式与原型模式的深度探索之旅

在这里插入图片描述
​🌈 个人主页:danci_
🔥 系列专栏:《设计模式》
💪🏻 制定明确可量化的目标,坚持默默的做事。
🚀 转载自:设计模式深度解析:单例模式与原型模式的深度探索之旅

设计模式深度解析:单例模式与原型模式的深度探索之旅

探索设计模式的魅力:“感受单例模式的力量与神秘” - 掌握编程的王牌技巧文章浏览阅读10k次,点赞44次,收藏42次。在软件开发的赛场上,单例模式以其独特的魅力长期占据着重要的地位。作为设计模式中的一员,它在整个软件工程的棋盘上扮演着关键性角色。本文将带你深入探索单例模式的神秘面纱,从历史渊源到现代应用,从基础实现到高级技巧,经过戏剧性的转折和层层推进,我们将一步步揭开这一模式背后的秘密。文章串起时间的线索,带你重回单例模式的起源,理解它在软件工程历史中的地位。经过时间的流逝,单例模式不仅保持了其原有的魅力,而且随着新的编程语言和技术的发展,还展示出了新的活力和应用场景。https://blog.csdn.net/danci_/article/details/135687924

探索设计模式的魅力:一次设计,多次利用,深入理解原型模式的设计艺术文章浏览阅读16k次,点赞126次,收藏83次。原型模式是一种设计模式,属于创建型模式的一种,它用于创建重复的对象,同时又能保持性能。在原型模式中,通过复制现有对象的原型来创建新对象,而不是通过实例化类来创建对象。这样做可以避免耗费过多的资源开销,特别是在对象的创建过程比较复杂或耗时的情况下。
在原型模式中,原型对象实现一个克隆方法(Clone)用于复制自身,当需要创建新对象时,就可以通过克隆原型对象来得到一个新的对象副本。原型模式通常包括浅拷贝和深拷贝两种形式,浅拷贝只复制对象本身,而深拷贝则会连同对象引用的其他对象一起复制,因此能够得到完全
https://blog.csdn.net/danci_/article/details/135739260

文章目录

  • 一、定义🌐
    • 单例模式:独一无二的存在 🤔
    • 原型模式:复制的艺术 😉
    • 模式对比</font></code>
  • 二、结构图🔍
    • 参与者👇
    • 适用场景
  • <code>三、易混场景💔<code>
    • 场景
    • 使用单例模式:独一无二的存在 🤔
    • 使用原型模式:复制的艺术 😉
    • 易混淆之处 😅</code>

一、定义🌐

在这里插入图片描述

单例模式:独一无二的存在 🤔

✨ 通过确保类的唯一实例存在和全局可访问性,实现资源的有效管理和全局状态的统一控制。

 作用

在软件设计中,单例模式通过将构造函数私有化、创建静态私有变量以及提供公共的静态方法来获取实例等方式,确保了类的唯一实例的创建和访问。这种方式可以有效地节省系统资源,避免因为创建多个实例而导致的资源浪费和性能下降。

 如何封装对象的创建过程
    单例模式是一种巧妙的设计,它通过封装对象的创建过程,确保一个类在应用中只有一个实例,并提供一个全局访问点来获取这个实例。下面是对单例模式如何封装对象创建过程的详细描述:👇
  1. 隐藏构造函数:
    单例模式将类的构造函数私有化(设为私有或者受保护的),这样外部代码就无法直接通过new关键字来创建类的实例。通过隐藏构造函数,单例模式限制了外部对类实例化的权限,从而确保整个应用中只能通过特定的途径来获取类的实例。

  2. 提供静态访问方法:
    单例模式提供了一个静态的访问方法(通常是getInstance()方法),用于获取类的唯一实例。这个方法首先检查类的实例是否已经存在,如果存在则直接返回这个实例;如果不存在,则通过私有构造函数创建一个新的实例,并将其保存在一个静态的私有变量中,然后再返回这个实例。

  3. 确保线程安全:
    在多线程环境下,如果不采取适当的同步措施,可能会出现多个线程同时创建实例的情况,从而破坏单例的唯一性。因此,单例模式通常会通过双重检查锁定(double-checked locking)或其他线程安全机制来确保getInstance()方法的线程安全。

  4. 延迟实例化:
    有些单例模式的实现采用了延迟实例化的策略,即getInstance()方法第一次被调用时才创建类的实例。这种策略的好处是可以节省系统资源,因为只有当类的实例真正被需要时才会被创建。

    通过封装对象的创建过程,单例模式提供了一种机制,使得开发者能够控制对象的创建和访问,从而实现了资源的有效管理和代码的简洁性。单例模式常用于那些只需要一个实例的类,如配置管理类、日志记录类、线程池类等。

原型模式:复制的艺术 😉

✨ 利用复制机制来简化对象的创建过程,提高开发效率,并保证新对象的正确性和一致性。

 作用

减少重复劳动和资源浪费。它允许开发者直接复用已有对象的状态和行为,从而避免不必要的重复初始化操作。同时,通过复制现有对象,原型模式可以生成复杂对象的精确副本,保证了新对象与原型对象在功能和行为上的一致性。

 如何封装对象的创建过程
    通过定义一个原型接口,并允许子类实现接口的克隆方法。这个过程确保了当我们需要创建新对象时,不必通过传统的构造器,而是直接利用已有的原型对象进行复制。
    具体来说,原型模式封装对象创建过程的方式如下:👇
  1. 定义原型接口:
    ✨ 这个接口声明了一个克隆自身的方法,通常是 clone()。所有具体原型类都将实现这个接口,并提供具体的克隆方法实现。

  2. 实现克隆方法:
    ✨ 每个具体的原型类都需要实现 clone() 方法,该方法负责创建并返回原型对象的一个副本。这个副本通常是通过深拷贝(deep copy)得到的,以确保新对象与原对象在内存上是完全独立的,修改新对象不会影响到原对象。

  3. 通过复制原型来创建新对象:
    ✨ 当需要创建新对象时,客户端代码不再通过调用构造器,而是直接获取一个原型对象,并调用其 clone() 方法来得到一个新的对象。由于这个过程是封装在原型对象内部的,客户端代码不需要关心对象是如何被创建的,只需关注如何使用复制得到的新对象。

  4. 提供全局访问点:
    ✨ 通常会有一个工厂方法或类似机制来充当全局访问点,负责创建并返回原型对象的实例。这样,客户端代码就可以通过这个访问点来获取原型对象,并进行复制操作。

    通过这种方式,原型模式将对象的创建过程封装在原型对象内部,对外提供了统一的接口来创建新对象。这使得对象的创建过程更加灵活和可控制,同时减少了客户端代码与具体对象创建逻辑的耦合度。

    原型模式在需要频繁创建相似对象或对象创建过程比较复杂的情况下非常有用。例如,在需要大量相似但又不完全相同对象的游戏开发中,可以使用原型模式来快速生成游戏中的角色或道具。

模式对比

    为便于对比理解,总结如下图所示:
在这里插入图片描述
    🌟 单例模式的优点在于减少内存开销、简化对象访问,并避免全局状态的混乱然而,它也存在一些缺点,如过度使用可能导致代码难以理解和维护,以及在多线程环境下需要谨慎处理同步问题。

    🌟 原型模式的优点在于提高了对象的创建效率,降低了系统开销此外,通过复制现有对象来创建新对象,还可以保证新对象与原型对象的一致性。然而,它也可能导致一些潜在的问题,如深拷贝与浅拷贝的选择、对象状态的继承等需要仔细考虑。

    进一步来说,单例模式确保一个类仅有一个实例,强调唯一性与全局访问点;而原型模式通过复制现有对象创建新对象,注重对象的快速生成与复用。

    单例模式与原型模式在软件设计中各自扮演着不同的角色。选择使用哪种模式取决于具体的应用场景和需求。在实际开发中,我们可以根据项目的实际情况和需求来选择合适的模式,以提高代码的质量和性能。

二、结构图🔍

在这里插入图片描述

参与者👇

 1. 单例模式:独一无二的存在
    ⭐ 单例类(Singleton Class):
    这是单例模式的核心部分,它负责创建自己的唯一实例。
     单例类通常包含一个私有的构造函数,以防止外部类通过new关键字创建多个实例。
     它还提供一个公共的静态方法(如getInstance()),用于获取该类的唯一实例。如果实例不存在,则该方法会创建一个新实例;如果实例已经存在,则直接返回该实例。

    ⭐ 客户端(Client):
    客户端是使用单例对象的代码部分。
     客户端通过调用单例类的静态方法来获取单例对象,并使用该对象进行操作。
     客户端无需知道单例对象是如何创建的,只需知道如何获取和使用它。

    ⭐ 单例实例(Singleton Instance):
    这是单例类创建并维护的唯一对象实例。
     所有对单例类的请求都会返回这个唯一的实例。
 

    在某些实现中,可能还会涉及到以下参与者:
    ⭐ 静态初始化器(Static Initializer):
     在某些实现中,单例实例可能会在静态初始化块中被创建。这样做的好处是线程安全且实例的创建是懒加载的(即只在首次使用时创建)。但需要注意的是,如果静态初始化器抛出异常,那么该异常将在类加载时被抛出,这可能会导致类加载失败。

    ⭐ 同步机制(Synchronization Mechanism):
    在多线程环境中,为了保证单例的唯一性,可能需要在获取实例的方法上添加同步机制。但过度的同步可能会影响性能,因此需要谨慎使用。
 

 2. 原型模式:复制的艺术
    🥂 原型类(Prototype Class):
    原型类是定义了如何创建新对象的基础类。它通常实现了一个克隆方法(如clone()),该方法负责创建并返回原型对象的一个副本。
     原型类可以包含创建对象所需的所有状态信息和必要的行为。

    🥂 具体原型类(Concrete Prototype Class):
    具体原型类是原型类的子类,它实现了原型类所定义的克隆方法,并可能添加了一些额外的状态和行为。
     客户端通常通过具体原型类来创建新的对象实例。

    🥂 客户端(Client):
    客户端是使用原型模式来创建对象的代码部分。
     客户端首先会获取一个原型对象(可以是通过工厂方法或直接从具体原型类实例化得到的)。
     然后,客户端通过调用原型对象的克隆方法来创建新的对象实例,而无需从头开始构建对象。

    🥂 克隆的对象(Cloned Objects):
    这些是通过调用原型对象的克隆方法创建的新对象实例。
     克隆的对象是原型对象的副本,它们具有与原型对象相同的初始状态和行为。

    🥂 深拷贝与浅拷贝机制:
    在原型模式中,克隆方法的实现是关键。根据具体需求,可能实现深拷贝或浅拷贝。
     深拷贝会创建一个完全独立的新对象,包括其所有子对象和引用的数据。
     浅拷贝则只复制对象的引用,不复制引用的实际对象。

适用场景

在这里插入图片描述
    单例模式和原型模式往往根据具体需求和场景进行选择和搭配使用。例如,在某些系统中,可能需要使用单例模式来管理数据库连接池,而连接池中的连接对象则可以使用原型模式进行复制和共享。因此,在选择使用哪种模式时,需要综合考虑系统的整体架构、性能需求以及开发效率等因素。

 

三、易混场景💔

在这里插入图片描述

场景

✨ 在图形渲染应用中,通常需要管理一个渲染上下文(如OpenGL上下文),这个上下文负责处理所有的图形绘制操作。

  这样的上下文在应用中通常只需要一个实例,因为多个实例可能会导致资源冲突或不必要的开销。但是,有时我们可能需要在不同的线程或任务中使用相同配置的渲染上下文,这时就需要考虑是否复制上下文。

使用单例模式:独一无二的存在 🤔

如果渲染上下文是全局唯一的,且所有图形绘制操作都需要通过这个唯一的上下文进行,那么单例模式是一个很好的选择。

  操作如下
    1. 定义一个单例类,负责创建和管理渲染上下文。
    2. 在类的内部实现一个私有的静态实例,并提供一个公共的静态方法来获取这个实例。
    3. 确保构造函数是私有的,以防止外部代码创建新的实例。

  效果
    1. 确保全局只有一个渲染上下文实例。
    2. 简化了对渲染上下文的访问,任何需要绘制图形的代码都可以通过单例类获取上下文。

  优点
    1. 节省资源:只创建一个渲染上下文实例。
    2. 避免冲突:确保所有图形操作都在同一个上下文中进行,避免了可能的资源冲突。

  缺点
    1. 灵活性差:如果需要多个具有不同配置的渲染上下文,单例模式将无法满足需求。
    2. 不利于单元测试:由于单例类的全局性,对其进行单元测试可能会比较困难。

使用原型模式:复制的艺术 😉

如果需要在不同的线程或任务中使用相同配置的渲染上下文,但又不希望共享同一个实例(可能是出于线程安全或性能优化的考虑),那么原型模式可能是一个更好的选择。

  操作如下
    1. 定义一个原型类,负责创建和管理渲染上下文。
    2. 在类中实现克隆方法(如Java中的clone()方法或实现Cloneable接口),以允许创建具有相同配置的新实例。
    3. 外部代码可以通过调用原型类的克隆方法来创建新的渲染上下文实例。

  效果
    1. 允许创建多个具有相同配置的渲染上下文实例。
    2. 每个实例都是独立的,可以在不同的线程或任务中安全地使用。

  优点
    1. 灵活性高:可以根据需要创建多个具有相同配置的渲染上下文实例。
    2. 线程安全:每个实例都是独立的,避免了线程间的资源冲突。

  缺点
    1. 资源消耗大:需要创建和管理多个渲染上下文实例,可能会增加内存消耗和初始化成本。
    2. 实现复杂:需要正确实现克隆方法,以确保新实例与原始实例具有相同的配置状态。这可能会增加代码的复杂性和出错的可能性。

  

易混淆之处 😅

  …
 
 
    注:本文只转载部分内容,三连 或 更多请跳转原文。

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

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

相关文章

鸿蒙Harmony应用开发—ArkTS声明式开发(画布组件:Canvas)

提供画布组件&#xff0c;用于自定义绘制图形。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 不支持。 接口 Canvas(context?: CanvasRenderingContext2D) 从API version 9开始&…

AI实景无人直播系统源代码开发部署流程

一、 开发流程分享 需求分析&#xff1a;与客户明确需求&#xff0c;确定无人直播系统的功能和特性。 设计系统架构&#xff1a;根据需求分析的结果&#xff0c;设计系统的架构&#xff0c;包括前后端的组成和各个模块的功能划分。 编写源代码&#xff1a;根据系统架构设计&a…

一款基于 SpringCloud 开发的AI聊天机器人系统,已对接GPT-4.0,非常强大

简介 一个基于SpringCloud的Chatgpt机器人&#xff0c;已对接GPT-3.5、GPT-4.0、百度文心一言、stable diffusion AI绘图、Midjourney绘图。用户可以在界面上与聊天机器人进行对话&#xff0c;聊天机器人会根据用户的输入自动生成回复。同时也支持画图&#xff0c;用户输入文本…

解决Vue发布后新旧包切换点击路由报错问题

错误截图 解决方案&#xff1a; 1.修改vue.config.js output: {// filename: js/[name].[chunkhash].${timeUpdate}.js,// chunkFilename: js/[id].[chunkhash].${timeUpdate}.jsfilename: [name].[contenthash].js,chunkFilename: [name].[contenthash].chunk.js}2.路由中添…

MRP(VBA系列):1.检查生产计划中的设备是否有BOM

在所有运行的前面&#xff0c;我需要先做一个检查&#xff1a;生产计划中的设备是否有BOM&#xff0c;如果有的设备没有BOM&#xff0c;我不希望程序继续&#xff01; Tips&#xff1a;所有代码都是为目前任职公司编写&#xff0c;极大概率不适合其他公司&#xff0c;在这里发…

C++ 11

目录 1. 统一的列表初始化 1.1 &#xff5b;&#xff5d;初始化 1.2 std::initializer_list 2. decltype 3. 右值引用和移动语义 3.1 左值引用和右值引用 3.2 左值引用与右值引用比较 3.3 右值引用使用场景和意义 3.4 右值引用引用左值及其一些更深入的使用场景分析 3…

长安链开源社区发布2023年度长安链优秀应用案例

1月27日结束的“长安链发布三周年庆暨生态年会”上&#xff0c;在国家区块链技术创新中心的指导下&#xff0c;长安链开源社区联合长安链生态联盟正式发布2023年度长安链行业示范案例、领域精品案例及特色创新案例。 本次评选面向2023年度应用长安链上线并取得应用成效的案例&…

国内ip地址范围多大?ip地址容易切换吗?

随着互联网的蓬勃发展&#xff0c;IP地址成为连接每一台设备和服务的纽带。对于一个庞大的网络市场而言&#xff0c;了解国内IP地址的范围及其背后的技术细节显得尤为重要。虎观代理小二将深入剖析国内IP地址的范围&#xff0c;带您走进这个庞大而复杂的网络世界。 什么是IP地…

BlenderGIS 快捷键E 报错问题 Report: Error

最新版的Blender4.0 对于 BlenderGIS2.28版本的插件不兼容&#xff0c;BlenderGIS2.28兼容Blender3.6.9及之前的版本&#xff0c;应该是BlenderGIS插件很久没更新了导致的。

Pytorch详细应用基础(全)

&#x1f525;博客主页&#xff1a; A_SHOWY&#x1f3a5;系列专栏&#xff1a;力扣刷题总结录 数据结构 云计算 数字图像处理 力扣每日一题_ 1.安装pytorch以及anaconda配置 尽量保持默认的通道&#xff0c;每次写指令把镜像地址写上就行。 defaults优先级是最低的&#…

【LeetCode 算法刷题笔记-路径篇】

1.0112. 路径总和 1.1 题目大意 描述&#xff1a;给定一个二叉树的根节点 root 和一个值 targetSum。 要求&#xff1a;判断该树中是否存在从根节点到叶子节点的路径&#xff0c;使得这条路径上所有节点值相加等于 targetSum。如果存在&#xff0c;返回 True&#xff1b;否则…

GPT-SoVITS语音合成服务器部署,可远程访问(全部代码和详细部署步骤)

GPT-SoVITS 是一个开源项目&#xff0c;它使用大约一分钟的语音数据便可以训练出一个优秀的TTS模型。 项目的核心技术是 Zero-shot TTS 和 Few-shot TTS。 Zero-shot TTS 可以让用户输入5秒钟的语音样本并立即体验转换后的语音&#xff0c;而 Few-shot TTS 则可以通过使用仅一…

《论文阅读》EmpDG:多分辨率交互式移情对话生成 COLING 2020

《论文阅读》EmpDG:多分辨率交互式移情对话生成 COLING 2020 前言简介模型架构共情生成器交互鉴别器损失函数前言 亲身阅读感受分享,细节画图解释,再也不用担心看不懂论文啦~ 无抄袭,无复制,纯手工敲击键盘~ 今天为大家带来的是《EmpDG: Multi-resolution Interactive E…

Java 面向对象编程进阶三(封装)

目录 封装(encapsulation) 封装的作用和含义 封装的实现—使用访问控制符 public 访问权限修饰符&#xff1a; protected 访问权限修饰符&#xff1a; 默认访问权限修饰符 private 访问权限修饰符 封装的一些处理 封装(encapsulation) 封装是面向对象三大特征之一。对于…

蓝牙耳机哪个品牌最好?2024口碑绝佳蓝牙耳机推荐分享

​随着生活水平的不断提高&#xff0c;蓝牙耳机已成为我们生活中不可或缺的一部分。它为我们提供了极大的便利&#xff0c;无论是在听音乐、观看视频还是进行电话通话时。面对市场上种类繁多的蓝牙耳机&#xff0c;我为你整理了几款表现很不错的耳机产品&#xff0c;希望能帮助…

亚信安慧AntDB数据库分布式架构剖析之snapshot receiver进程

本文主要介绍亚信安慧AntDB数据库的分布式架构下的特有进程之snapshot receiver的设计&#xff0c;这也是分布式架构的核心进程之一。 进程简介 该进程的作用从逻辑上解释包含两个方面&#xff1a; 同步快照&#xff0c;并且是作为通信的client端存在 同步事务号&#xff0c;…

【博客7.4】缤果Qt5_TWS串口调试助手V2.0 (高级篇)

超级好用的Qt5_TWS耳机串口调试助手 开发工具: qt-opensource-windows-x86-5.14.2 (编程语言C) 目录 前言 一、软件概要&#xff1a; 二、软件界面&#xff1a; 1.App演示 三、获取 >> 源码以及Git记录&#xff1a; 总结 前言 串口调试助手支持常用的50bps - 10M…

MyBatisPlus 之四:MP 的乐观锁和逻辑删除、分组、排序、链式的实现步骤

乐观锁 乐观锁是相对悲观锁而言的&#xff0c;乐观锁假设数据一般情况不会造成冲突&#xff0c;所以在数据进行提交更新的时候&#xff0c;才会正式对数据的冲突与否进行检测&#xff0c;如果冲突&#xff0c;则返回给用户异常信息&#xff0c;让用户决定如何去做。 乐观锁适用…

WannierTools安装教程

wanniertools简单介绍 开源软件包WannierTools&#xff0c;是一个用于研究新型拓扑材料的软件。此代码在紧束缚模型中工作&#xff0c;可以由另一个软件包Wannier90生成。 它可以通过计算Wilson loop来帮助对给定材料的拓扑相进行分类&#xff0c;通过角分辨光电发射(ARPES)和…

掘根宝典之C++正向迭代器和反向迭代器详解

简介 迭代器是一种用于遍历容器元素的对象。它提供了一种统一的访问方式&#xff0c;使程序员可以对容器中的元素进行逐个访问和操作&#xff0c;而不需要了解容器的内部实现细节。 C标准库里每个容器都定义了迭代器&#xff0c;这迭代器的名字就叫容器迭代器 迭代器的作用类…