设计模式面试题(二)

1.单例优缺点

单例模式是一种常用的设计模式,它确保一个类仅有一个实例,并提供一个全局访问点。单例模式的使用具有一定的优点,同时也伴随着一些潜在的缺点。

优点

  1. 资源控制:单例模式能够确保资源如数据库连接或文件系统的一致访问,防止资源冲突。
  2. 内存占用减少:由于实例唯一,单例模式帮助减少系统内存的使用,避免重复对象的创建和销毁。
  3. 全局访问点:提供了一个访问唯一实例的全局访问点,方便从系统任何其他代码位置访问该实例。
  4. 数据共享:单例实例作为全局实例,便于在不同的程序模块间共享数据。
  5. 延迟初始化:单例模式支持延迟初始化(懒汉式),仅在需要时创建实例,节省资源和减少启动时间。

缺点

  1. 违背单一职责原则:单例类除了管理自身的实例外,还承担了业务逻辑的职责,违背了单一职责原则。
  2. 全局状态引起的问题:单例模式在多线程环境下,如果不正确处理,会引入全局状态的问题,如实例在多线程间共享时可能出现同步问题。
  3. 对测试的影响:单例的全局状态使得单元测试变得困难,尤其是当单例类不遵循接口时,很难被Mock替代。
  4. 扩展困难:由于单例模式的实例是全局唯一的,扩展和修改单例类的功能可能会影响到所有使用该实例的地方。
  5. 隐藏依赖:单例模式的使用可能会隐藏类之间的依赖关系,而不是通过接口或构造函数注入,这降低了代码的可读性和可维护性。

结论

单例模式在需要控制资源访问或确保全局唯一性时非常有用,但是它也带来了一些设计上的挑战,尤其是在大型、复杂系统中。使用单例模式时应该仔细考虑其对系统设计的影响,尽可能地遵循设计原则,如依赖倒置原则和接口隔离原则,以保持代码的灵活性和可测试性。在某些情况下,考虑使用依赖注入框架来管理单例实例,可能是更好的选择。

2.单例模式使用注意事项

选择合适的单例模式创建方式依赖于应用的需求、资源的特性以及环境的限制。下面是几种常见的单例创建方式以及它们各自的适用场景:

1. 懒汉式(线程不安全)

  • 特点:实例在首次使用时创建。
  • 适用场景:单线程环境,或者实例创建开销小且在程序生命周期中很早就会被用到。

2. 懒汉式(线程安全)

  • 特点:实例在首次使用时创建,通过同步机制确保线程安全。
  • 适用场景:多线程环境,但对性能要求不是特别高,因为同步操作只需要在实例创建时执行一次,之后获取实例不再需要同步。

3. 饿汉式

  • 特点:类加载时就完成了实例的初始化,基于类加载机制避免了多线程的同步问题。
  • 适用场景:单例对象占用资源少,按需加载不是必须的场景,或者确保实例的创建不依赖于参数和配置设置。

4. 双重检查锁定(Double-Checked Locking)

  • 特点:在实例未初始化时才同步,避免了每次访问时的同步开销。
  • 适用场景:多线程环境中,需要延迟实例化并且确保实例只被创建一次。

5. 静态内部类

  • 特点:利用类加载机制保证初始化实例时只有一个线程。
  • 适用场景:既需要延迟加载,又要确保线程安全。静态内部类方式在很多情况下是最推荐的单例实现方式,它既能保证延迟加载,又能保证高效的线程安全。

6. 枚举方式

  • 特点:最简单的实现方式,通过Java枚举类型本身的特性,保证实例创建的安全性和唯一性。
  • 适用场景:实现单例的最佳方法之一。不仅能避免多线程同步问题,还能防止反序列化重新创建新的对象。

总结

  • 对于大部分多线程场景,双重检查锁定静态内部类方式是较好的选择,它们既保证了懒加载,又保证了高效的线程安全。
  • 如果单例类的实例在应用启动时就必须被使用,或者实例的创建开销不重要,可以选择饿汉式
  • 如果需要绝对的序列化安全,可以使用枚举方式实现单例。

在选择单例模式的实现方式时,应该根据实际需求和具体情况做出合理的决策。

3.单例防止反射漏洞攻击

在Java中,反射可以用来绕过私有构造函数的限制,从而创建多个单例对象的实例,这违反了单例模式的原则。为了防止这种反射攻击,可以采取一些措施确保单例类的安全性。

1. 抛出异常

在单例类的私有构造方法中检查实例是否已经存在,如果存在,则抛出一个异常。这样可以阻止通过反射创建第二个实例。

public class Singleton {private static Singleton instance;private Singleton() {if (instance != null) {throw new IllegalStateException("Instance already exists!");}}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}

2. 使用枚举实现单例

Java枚举类型(enum)提供了一种简单的方式来实现单例模式,而且枚举类型天然防止了通过反射和序列化攻击的可能性。

public enum Singleton {INSTANCE;public void someMethod() {// 方法实现}
}

在这种方法中,Singleton.INSTANCE总是返回相同的实例,JVM保证枚举值是全局唯一的。此外,Java禁止通过反射来创建枚举实例,这自然防止了通过反射创建新实例的漏洞。

3. 使用内部静态类

虽然使用内部静态类本身不能防止反射攻击,但结合私有构造方法内的安全检查,可以提供双重保障。

public class Singleton {private Singleton() {if (SingletonHolder.INSTANCE != null) {throw new IllegalStateException("Instance already exists!");}}private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance() {return SingletonHolder.INSTANCE;}
}

总结

  • 尽管可以通过在私有构造函数中添加检查来阻止反射创建第二个实例,但这种方法并非完美。它可能导致反射调用的代码抛出异常。
  • 使用枚举类型是防止反射攻击最简单也是最推荐的方法。枚举类型的单例不仅能避免多线程同步问题,还能防止反射和序列化攻击。
  • 应该注意的是,设计和实现单例时,除了考虑防止反射攻击外,还应该综合考虑其他安全性因素,如线程安全和防止序列化攻击。

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

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

相关文章

目标检测——监控下的汽车

一、重要性及意义 首先,车辆检测技术是保证视频监控系统正常运行的基础。通过监控摄像头实时获取的图像,可以自动检测出图像中的车辆,并进行车辆类型的分类和识别。这对于优化城市交通管理、实现智能交通系统具有重要意义。此外,…

【无标题】html中使用div标签的坏处

在HTML中使用<div>作为布局元素时&#xff0c;尽管它已经成为现代Web开发的标准做法之一&#xff0c;并且与CSS结合使用可以实现灵活、语义化的布局设计&#xff0c;但也存在以下潜在的坏处或挑战&#xff1a; 复杂度增加&#xff1a; - 学习曲线&#xff1a;对于初学者…

【SQL Server的详细使用教程】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

【QT+QGIS跨平台编译】056:【pdal_lepcc+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

点击查看专栏目录 文章目录 一、pdal_lepcc介绍二、pdal下载三、文件分析四、pro文件五、编译实践一、pdal_lepcc介绍 pdal_lepcc 是 PDAL(Point Data Abstraction Library)的一个插件,用于点云数据的压缩。它基于 EPCC(Entwine Point Cloud Compression)算法,提供了对点…

Go语言实现Redis分布式锁

基于go-redis的设计与实现 本文将基于go语言&#xff0c;使用了一个常用的go Redis客户端 go-redis库 , 一步一步探索与实现一个简单的Redis分布式锁。 代码&#xff1a;https://github.com/liwook/Redislock 连接Redis ​ func NewClient() *redis.Client {return redis.N…

51单片机入门之独立按键

目录 1.按键简介 2.独立按键控制LED亮灭 3.独立按键控制LED移位 1.按键简介 在生活中&#xff0c;我们常常会见到各种按键&#xff0c;我们的开发板上也有按键&#xff0c;就在左下角有四个按键&#xff0c;我们把它们叫做独立按键。 独立按键的原理比较简单&…

VUE实现下一页的功能

实现步骤&#xff1a;1、确定分页参数&#xff1a;确定当前页码和每页显示的数量&#xff1b;2、获取数据&#xff1a;使用vue的axios或其他http库向后端发送请求&#xff0c;传递当前页码和每页显示的数量作为参数&#xff1b;3、更新数据&#xff1a;在vue组件中&#xff0c;…

Qt与OpenCV实现图像模板匹配

在 Qt 中使用 OpenCV 实现模板匹配可以通过集成 OpenCV 库和使用其相关函数来完成。以下是一般的步骤&#xff1a; 安装 OpenCV&#xff1a;首先&#xff0c;确保你已经安装了 OpenCV 库&#xff0c;并将其配置到你的开发环境中。 创建 Qt 项目&#xff1a;使用 Qt creator 或…

VSCode 插件 Todo Tree 待办事项

官方介绍&#xff1a;这个扩展可以快速搜索工作区中的注释标签&#xff0c;并将它们显示在活动栏的树状图中 我们写代码的时候&#xff0c;难免会遇到一些情况需要标记或搁置&#xff0c;比如&#xff1a;前端开发者在编写页面的时候页面样式完成了&#xff0c;但是后端接口还…

【机器学习】《机器学习算法竞赛实战》第7章用户画像

文章目录 第7章 用户画像7.1 什么是用户画像7.2 标签系统7.2.1 标签分类方式7.2.2 多渠道获取标签7.2.3 标签体系框架 7.3 用户画像数据特征7.3.1 常见的数据形式7.3.2 文本挖掘算法7.3.3 神奇的嵌入表示7.3.4 相似度计算方法 7.4 用户画像的应用7.4.1 用户分析7.4.2 精准营销7…

RabbitMQ安装详细教程

&#xff08;一&#xff09;在Windows系统上安装Erlang的步骤如下&#xff1a; 打开Erlang的官方下载页面&#xff0c;选择适合你的Windows系统的版本进行下载。 下载完成后&#xff0c;双击运行下载的.exe文件&#xff0c;进入Erlang的安装向导。 在安装向导中&#xff0c;按…

vscode-keil一起用

安装插件 1、C/C Extension Pack 2、Keil Assistant 配置 重启生效&#xff01;&#xff01;&#xff01; 下载安装 Mingw 下载链接&#xff1a; 添加环境变量&#xff1a; 注意确认&#xff01;&#xff01;&#xff01; 报错 gccC:\迅雷下载\MinGW\MinGW\bin…

力扣爆刷第111天之CodeTop100五连刷41-45

力扣爆刷第111天之CodeTop100五连刷41-45 文章目录 力扣爆刷第111天之CodeTop100五连刷41-45一、232. 用栈实现队列二、4. 寻找两个正序数组的中位数三、31. 下一个排列四、69. x 的平方根五、8. 字符串转换整数 (atoi) 一、232. 用栈实现队列 题目链接&#xff1a;https://le…

注解(Annotation)

10.1 注解概述 10.1.1 什么是注解 注解&#xff08;Annotation&#xff09;是从JDK5.0开始引入&#xff0c;以“注解名”在代码中存在。例如&#xff1a; Override Deprecated SuppressWarnings(value”unchecked”) Annotation 可以像修饰符一样被使用&#xff0c;可用于修饰…

【八股】Spring MVC

什么是Spring MVC&#xff1f; Spring MVC 是 Spring 中的一个很重要的模块&#xff0c;是一个根据MVC架构推出的web开发框架&#xff0c;目的是为了简化Java的web开发 Spring MVC 执行流程&#xff1f; 现在一般都是前后端分离&#xff0c;根据接口去开发嘛&#xff0c;所以…

ChatGPT 之赋能提示词工程

原文&#xff1a;Chatgpt Empowers Your Prompt Engineering with AI Tools 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 介绍 在当今这个时代&#xff0c;设计和人工智能工具对于企业在不断发展的市场中蓬勃发展至关重要。ChatGPT 为探索一系列可能性提供了机会&am…

Visual Studio(VS) 搭建 QT 开发环境

Visual Studio(VS) 搭建 QT 开发环境 在当今的软件开发领域,Visual Studio(VS)是一款备受欢迎的集成开发环境(IDE),而 QT 则是一个强大的跨平台应用程序框架。将两者结合使用,可以为开发人员提供高效、便捷的开发体验。本文将详细介绍如何在 VS2022 中搭建 QT 开发环…

中兴天机A31 A31PRO 5G zte A2122H te A2022H 解锁BootLoader root权限 教程magisk,原厂刷机包

zte A2122H P768A02 zte A2022H P875A02 中兴天机A31 A31PRO 5G zte A2122H te A2022H 解锁BootLoader root教程magisk&#xff0c;原厂刷机包 感谢 某大神支持&#xff0c;已经解锁root 刷了面具&#xff1b; 中兴天机A31 A31PRO 5G zte A2122H te A2022H 解锁BootLoad…

2024.3.16力扣每日一题——矩阵中移动的最大次数

2024.3.16 题目来源我的题解方法一 深度优先遍历&#xff08;超时&#xff09;方法二 动态规划方法三 广度优先遍历 题目来源 力扣每日一题&#xff1b;题序&#xff1a;2684 我的题解 方法一 深度优先遍历&#xff08;超时&#xff09; 从第一列的每一行开始进行深度优先遍…

深入浅出 -- 系统架构之单体架构和微服务架构的区别

在软件开发中&#xff0c;架构设计是非常重要的一环。架构设计不仅决定了软件系统的性能、可维护性和扩展性&#xff0c;还直接关系到开发成本和项目进度。目前&#xff0c;主流的架构设计模式有两种&#xff0c;一种是单体架构&#xff0c;另一种是微服务架构。本文将详细介绍…