设计模式之创建型设计模式(一):单例模式 原型模式

单例模式 Singleton

1、什么是单例模式

在软件设计中,单例模式是一种创建型设计模式,其主要目的是确保一个类只有一个实例,并提供一个全局访问点。

这意味着无论何时需要该类的实例,都可以获得相同的实例,而不会创建新的对象。

单例模式通常用于控制对资源的访问,例如配置文件、数据库连接,或者共享的实例。

2、为什么使用单例模式

  1. 资源共享:单例模式可以确保在整个应用程序中只有一个实例,从而节省系统资源,避免多次创建相同对象。
  2. 全局访问:通过单例模式,可以在任何需要时轻松访问该类的实例,而无需传递它作为参数。
  3. 懒加载:单例模式可以实现懒加载,即只有在需要时才创建实例,而不是在应用程序启动时就创建。

3、如何实现单例模式

示例场景:设计实现一个 Logger 类,用于记录应用程序中的日志信息。

非单例模式的实现
public class Logger {private List<String> logs = new ArrayList<>();public void log(String message) {logs.add(message);}
}// 在应用程序的不同部分创建Logger实例
Logger logger1 = new Logger();
Logger logger2 = new Logger();logger1.log("Message from logger1");
logger2.log("Message from logger2");System.out.println(logger1.getLogs());  // ['Message from logger1']
System.out.println(logger2.getLogs());  // ['Message from logger2']
单例模式的实现
public class Logger {private static Logger instance;  // 单例实例private List<String> logs = new ArrayList<>();private Logger() {}public static Logger getInstance() {if (instance == null) {instance = new Logger();}return instance;}public void log(String message) {logs.add(message);}public List<String> getLogs() {return logs;}
}// 在应用程序的不同部分获取Logger实例
Logger logger1 = Logger.getInstance();
Logger logger2 = Logger.getInstance();logger1.log("Message from logger1");
logger2.log("Message from logger2");System.out.println(logger1.getLogs());  // ['Message from logger1', 'Message from logger2']
System.out.println(logger2.getLogs());  // ['Message from logger1', 'Message from logger2']
代码对比说明
  1. 资源共享:使用单例模式后,Logger 实例在整个应用程序中是唯一的,确保了日志的全局共享,避免了每次创建实例都生成新对象的问题。
  2. 全局访问:单例模式允许在应用程序的任何地方访问相同的 Logger 实例,而不必传递它。这提高了代码的简洁性和可维护性。
  3. 懒加载:单例模式的实现中,通过 getInstance 方法进行了懒加载,只有在实例不存在时才创建。这确保了在应用程序启动时不会预先创建实例,而是在需要时才进行创建,提高了效率。

4、是否存在缺陷和不足

  1. 全局状态:单例模式引入了全局状态,可能会导致代码的耦合性增加。由于单例在整个应用程序中都是可见的,其他部分可能难以预测它的状态,从而使代码难以理解和维护。
  2. 并发控制:在多线程环境中,需要考虑并发控制的问题。当多个线程同时尝试第一次获取单例实例时,可能会导致创建多个实例。为了解决这个问题,需要引入同步机制,但这会带来性能的开销。
  3. 隐藏依赖关系:使用单例模式可能导致隐藏了类之间的依赖关系,因为它可以在任何地方访问单例实例。这使得代码的结构变得不够清晰,降低了模块化的优势。
  4. 单一职责原则破坏:单例模式通常负责两个职责控制实例化过程和提供全局访问点。这可能违反了单一职责原则,使得代码的职责不够清晰。
  5. 测试困难:由于单例模式创建实例的逻辑通常包含在类内部,很难进行单元测试。测试过程可能会依赖于全局状态,导致测试的不确定性。

5、如何缓解缺陷和不足

  1. 使用依赖注入:考虑使用依赖注入来解决单例模式引入的全局状态问题。通过将依赖项传递给需要它们的类,可以更好地控制类之间的关系。
  2. 懒加载与双重检查锁定:在多线程环境中,可以使用懒加载和双重检查锁定等技术来确保实例的唯一性,并提高性能。
  3. 考虑其他创建型模式:根据具体需求,考虑其他创建型设计模式,如工厂方法模式或建造者模式,以避免单例模式的一些限制。
  4. 避免过度使用:单例模式并不适用于所有情况,避免过度使用。在确保有明确需求时使用,而不是为了方便而滥用。

虽然单例模式存在一些缺点,但在许多情况下,它仍然是一种有效的设计选择。在使用单例模式时,需要仔细权衡其优点和缺点,并根据具体情况选择合适的设计方式。

原型模式 Prototype

1、什么是原型模式

原型模式是一种创建型设计模式,核心思想是通过复制现有对象来创建新对象,而不是通过实例化类,这种创建新对象的方式更加高效,尤其当新对象的创建成本较高时,使用原型模式可以提高性能。

2、为什么使用原型模式

  1. 性能提升:当新对象的创建成本较高时,通过复制现有对象可以避免重复执行初始化和配置的开销,提高对象创建的效率。
  2. 灵活性:原型模式可以在运行时动态配置对象,通过克隆可以得到一个与原始对象相似的新对象,而无需修改结构。
  3. 简化对象创建:原型模式隐藏了对象的创建细节,使得对象的创建更加简单和统一。

3、如何实现原型模式

非原型模式的实现
public class Book {private String title;private String author;public Book(String title, String author) {this.title = title;this.author = author;}// Getters and setters...public Book clone() {return new Book(this.title, this.author);}
}
原型模式的实现
public class Book implements Cloneable {private String title;private String author;public Book(String title, String author) {this.title = title;this.author = author;}// Getters and setters...@Overridepublic Book clone() {try {return (Book) super.clone();} catch (CloneNotSupportedException e) {return null;}}
}

4、是否存在缺陷和不足

  1. 深克隆问题:默认的 clone 方法是浅克隆,即只克隆对象本身,而不克隆其引用类型的成员变量。如果对象包含引用类型的成员变量,可能需要进行深克隆,以避免共享引用对象。
  2. 构造函数不执行:在使用原型模式时,对象的构造函数不会执行,这可能导致某些初始化逻辑未被执行。

5、如何缓解缺陷和不足

  1. 深克隆的实现:如果需要深克隆,可以通过重写 clone 方法,手动克隆引用类型的成员变量,确保新对象独立于原始对象。
  2. 初始化方法:在原型对象中提供一个初始化方法,可以在克隆对象后手动调用该方法,以确保必要的初始化逻辑得以执行。

通过以上缓解措施,可以更好地应对深克隆和构造函数不执行等问题,使得原型模式更加灵活和实用,在实际应用中,根据具体需求和场景选择是否使用原型模式。

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

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

相关文章

使用VBA快速统计词组词频(多单词组合)(2/2)

实例需求&#xff1a;产品清单如A列所示&#xff0c;现在如下统计多单词组合词组词频。 在上一篇博客中《使用VBA快速统计词组词频(多单词组合)&#xff08;1/2&#xff09;》讲解了如何实现双词的词频统计。 本文将讲解如何实现3词的词频统计&#xff0c;掌握实现方法之后&a…

Mac如何安装stable diffusion

今天跟大家一起在Mac电脑上安装下stable diffusion&#xff0c;在midjourney等模型收费的情况下如何用自己的电脑算力用上免费的画图大模型呢&#xff1f;来吧一起实操起来 一、安装homebrew 官网地址&#xff1a;Homebrew — The Missing Package Manager for macOS (or Lin…

SQL进阶理论篇(十):数据库中的锁

文章目录 简介按照锁的粒度进行划分从数据库管理的角度进行划分从程序员的角度进行划分为什么共享锁会发生死锁&#xff1f;参考文献 简介 索引和锁&#xff0c;是数据库中的两个核心知识点。 索引的相关知识点&#xff0c;在之前的几章里我们已经介绍的差不多了。接下来我们…

[pasecactf_2019]flask_ssti proc ssti config

其实这个很简单 Linux的/proc/self/学习-CSDN博客 首先ssti 直接fenjing一把锁了 这里被加密后 存储在 config中了 然后我们去config中查看即可 {{config}} 可以获取到flag的值 -M7\x10wd94\x02!-\x0eL\x0c;\x07(DKO\r\x17!2R4\x02\rO\x0bsT#-\x1cZ\x1dG然后就可以写代码解…

MNIST内置手写数字数据集的实现

torchvision库 torchivision库是PyTorch中用来处理图像和视频的一个辅助库&#xff0c;接下来我们就会使用torchvision库加载内置的数据集进行分类模型的演示 为了统一数据加载和处理代码&#xff0c;PyTorch提供了两个类用于处理数据加载&#xff0c;他们分别是torch.utils.…

机器视觉技术与应用实战(开运算、闭运算、细化)

开运算和闭运算的基础是膨胀和腐蚀&#xff0c;可以在看本文章前先阅读这篇文章机器视觉技术与应用实战&#xff08;Chapter Two-04&#xff09;-CSDN博客 开运算&#xff1a;先腐蚀后膨胀。开运算可以使图像的轮廓变得光滑&#xff0c;具有断开狭窄的间断和消除细小突出物的作…

饥荒Mod 开发(十五):小地图显示物品

饥荒Mod 开发(十四)&#xff1a;制作屏幕弹窗 本篇源码 饥荒中按下Tab键可以显示地图&#xff0c;刚开始进入游戏的时候地图是未探索状态&#xff0c;所以我们并不知道地图上面的物品分布情况。并且地图上只会显示很少一部分的物品&#xff0c;比如树枝&#xff0c;草&#xf…

C++二维数组(4)

蛇形遍历 题目描述&#xff1a;用数字1,2,3,4,...,n*n这n2个数蛇形填充规模为n*n的方阵。 蛇形填充方法为&#xff1a; 对于每一条左下-右上的斜线&#xff0c;从左上到右下依次编号1,2,...,2n-1&#xff1b;按编号从小到大的顺序&#xff0c;将数字从小到大填入各 条斜线&…

链表基础知识(二、双向链表头插、尾插、头删、尾删、查找、删除、插入)

目录 一、双向链表的概念 二、 双向链表的优缺点分析​与对比 2.1双向链表特点&#xff1a; 2.2双链表的优劣&#xff1a; 2.3循环链表的优劣 2.4 顺序表和双向链表的优缺点分析​ 三、带头双向循环链表增删改查实现 3.1SList.c 3.2创建一个新节点、头节点 3.3头插 3.…

C# WPF上位机开发(知识产权ip保护)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 上位机软件如果是和硬件模块搭配开发&#xff0c;这个时候大部分上位机基本上都是白送的&#xff0c;不会收取相关的费用。但是&#xff0c;如果上…

chrome升级后,调试vue在控制台输出总是显示cjs.js

当前chrome版本120.0.6099.72 在vue中使用console.log输出时&#xff0c;总是显示cjs.js多少多少行&#xff0c;不能显示源文件名及行数 【解决方案】 打开控制台的设置 左侧找到“Ignore List”&#xff0c;取消勾选"enable Lgnore Listing"&#xff0c;并重启chr…

【Jmeter】Jmeter基础6-Jmeter元件介绍之前置处理器

前置处理器主要用于处理请求前的准备工作&#xff0c;如&#xff1a;参数、环境变量的设置等。 2.6.1、JSR223预处理程序 作用&#xff1a;请求前的准备工作。 参数说明&#xff1a; 语言&#xff1a;开发脚本所使用的语言&#xff0c;可通过下拉列表选择。参数&#xff1a;传…

Linux实操——安装Mysql

安装Mysql 一、检查是否已经安装了mariadb数据库,并卸载二、下载mysql包&#xff0c;并通过ftp上传到服务器三、解压安装包四、创建数据存储文件夹五、创建执行mysqld命令的用户&#xff0c;并初始化mysql六、启用传输安全七、启动mysql&#xff0c;验证是否安装成功 总结 博主…

【Hive】——DDL(DATABASE)

1 概述 2 创建数据库 create database if not exists test_database comment "this is my first db" with dbproperties (createdByAllen);3 描述数据库信息 describe 可以简写为desc extended 可以展示更多信息 describe database test_database; describe databa…

技术分享 | 接口测试价值与体系

如果把测试简单分为两类&#xff0c;那么就是客户端测试和服务端测试。移动端的测试包括 UI 测试&#xff0c;兼容性测试等&#xff0c;服务端测试包括接口测试。接口测试检查数据的交换、传递和控制管理过程。它绕过了客户端&#xff0c;直接对服务端进行测试。 接口测试的价值…

链表之带头双向循环链表(C语言版)

我们之前已经介绍过链表的知识了&#xff0c;这里我们直接开始实现带头双向循环链表 数据结构之单链表&#xff08;不带头单向非循环链表&#xff09;-CSDN博客 第一步&#xff1a;定义结构体 //定义结构体 typedef int SLTDateType; typedef struct Listnode {SLTDateType d…

字符设备驱动框架的编写

一. 简介 我们在学习裸机或者 STM32 的时候关于驱动的开发就是初始化相应的外设寄存器&#xff0c;在 Linux 驱动开发中&#xff0c;肯定也是要初始化相应的外设寄存器。 只是在 Linux 驱动开发中&#xff0c; 我们需要按照其规定的框架来编写驱动&#xff0c;所以说学 …

【HTML5、CSS3】新增特性总结!

文章目录 23 HTML5 新增特性23.1 语义化标签23.2 多媒体标签23.2.1 视频<video>标签23.2.2 音频<audio>标签 23.3 input属性值23.4 表单属性 24 CSS3 新增特性24.1 属性选择器24.2 结构伪类选择器24.2.1 选择第n个元素24.2.2 常用的6个结构伪类选择器 24.3 伪元素选…

如何用Python向图像中加入噪声

我们在做机器视觉项目的过程中&#xff0c;有的时候需要向图像中加入噪声。Pytorch本身不支持类似的功能&#xff0c;如果自己写的话&#xff0c;不但麻烦&#xff0c;而且容易出错。好在skimage支持这个功能。代码如下&#xff1a; import skimage import matplotlib.pyplot …

抚琴成一快-布鲁斯

布鲁斯 0.理论1.音阶1.大调布鲁斯音阶2.小调布鲁斯音阶 1.基础1.shuffle节奏制音2.十二小节3.和弦4.小调五声音阶 2.演奏手法1.Lamp and Lamp1.基础和声进行2.进阶和声进行1.quick change2. call and respond:3.回旋句 2.Box1.基础和声进行2.进阶和声进行 3.Boogie1.基础节奏2.…