Java进阶篇设计模式之一 ----- 单例模式

前言

在刚学编程没多久就听说过设计模式的大名,不过由于当时还是个彻彻底底的菜鸟,并没有去触碰。直到在开始工作中对简单的业务代码较为熟悉之后,才正式的接触设计模式。当时最早接触的设计模式是工厂模式,不过本文讲的是单例模式,这里就留着下篇文章中在讲解。至于为什么先讲解单例模式? 那是因为单例模式是设计模式中最简单的... 。凡事总有个先后顺序,所以就先易后难了。好了,废话不多说了,开始进入正片。

设计模式简介

说明:这里说了的简介就是真的 “简介”。

什么是设计模式

设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。

为什么使用设计模式

使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。

设计模式类型

设计模式有23种类型。按照主要分类可以分为三大类:

一、创建型模式

这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。

  • 单例模式
  • 工厂模式
  • 抽象工厂模式
  • 建造者模式
  • 原型模式

二、结构型模式

这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。

  • 适配器模式
  • 桥接模式
  • 过滤器模式
  • 组合模式
  • 装饰器模式
  • 外观模式
  • 享元模式
  • 代理模式

三、行为型模式

这些设计模式特别关注对象之间的通信。

  • 责任链模式
  • 命令模式
  • 解释器模式
  • 迭代器模式
  • 中介者模式
  • 备忘录模式
  • 观察者模式
  • 状态模式
  • 空对象模式
  • 策略模式
  • 模板模式
  • 访问者模式

设计模式的原则

设计模式的六大原则

  1. 开闭原则:对扩展开放,对修改关闭。
  2. 里氏代换原则:对开闭原则的补充。任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。
  3. 依赖倒转原则:针对接口编程,依赖于抽象而不依赖于具体。
  4. 接口隔离原则:尽量使用多个隔离的接口,为了降低类之间的耦合度。
  5. 迪米特法则:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
  6. 合成复用原则:尽量使用合成/聚合的方式,而不是使用继承。

单例模式

什么是单例模式

保证一个系统中的某个类只有一个实例而且该实例易于外界访问。例如Windows界面的任务管理器就可以看做是一个单例。

单例模式的使用场景

在程序中比较常用的是数据库连接池线程池日志对象等等。

单例模式使用

最早我们在学习单例模式的时候,基本都会接触这两种模式:饿汉式和饱汉式(懒汉式)。
那我们先来看看这两个模式的实现。

饿汉式
定义一个私有的构造方法,并将自身的实例对象设置为一个私有属性,并加上static和final修饰符,然后通过公共的静态方法调用返回实例。

 class SingletonTest1 {  private SingletonTest1() {  }  private static final SingletonTest1 instance = new SingletonTest1();  public static SingletonTest1 getInstance() {  return instance;  }  
}

饱汉式
定义一个私有的构造方法,定义一个该类静态私有的变量,然后定义一个公共的静态方法,对该类的值进行空判断,不为空直接返回,否则重新构建一个。

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

简单的介绍了这两种的模式,然后我们再来看看这两种模式的优缺点吧。
饿汉式

  • 优点:写起来很简单,并且不会因为不加synchronized关键字而造成的线程不安全问题。
  • 缺点:当该类被加载的时候,会初始化该实例和静态变量并被创建并分配内存空间,并且会一直占用内存。

饱汉式

  • 优点:写起来很简单,在第一次调用的时候才会初始化,节省了内存。
  • 缺点:线程不安全,多个线程调用可能会出现多个实例。
  • 总结:书写简单,线程不安全,效率还行。

虽然 饱汉式可以通过加上synchronized关键字保证线程安全。但是效率方法来说还不说是最优。

这里在介绍下个人认为在JDK1.5之前最优的两种写法,一种是静态内部类,另一种是双重锁检查

静态内部类
定义一个私有的构造方法,定义一个该类私有静态的内部类,然后在内部类中定义一个该类的静态变量,然后通过公共的final修饰的静态方法调用返回实例。

  class  SingletonTest4 {private SingletonTest4(){}private static class SingletonTest5{private static SingletonTest4 instance = new SingletonTest4();}public static final SingletonTest4 getInstance(){return SingletonTest5.instance;}}

因为该类的内部类是私有的,除了对外公布的公共静态方法getInstance(),是无法访问的。因为它是延迟加载,所以读取读取实例的时候不会进行同步,几乎没有性能的缺陷,而且还是线程安全的,并且不依赖JDK的版本。

双重锁检查
定义一个私有构造方法,通过volatile定义静态私有变量,保证了该变量的可见性,然后定义一个共有的静态方法,第一次对该对象实例化时与否判断,不为空直接返回,提升效率;然后使用synchronized 进行同步代码块,防止对象未初始化时,在多线程访问该对象在第一次创建后,再次重复的被创建;然后第二次对该对象实例化时与否判断,如果未初始化,则初始化,否则直接返回该实例。

  class SingletonTest6 { private SingletonTest6() { }   private static volatile SingletonTest6 instance;  public static SingletonTest6 getIstance() { if (instance == null) {synchronized (SingletonTest6.class) {if (instance == null) {instance = new SingletonTest6();   }   }   }   return instance;   }   }  

这种模式在很长的一段时间内可以说是最优的了,内存占用低,效率高,线程安全,多线程操作原子性。但是有个缺点就是书写麻烦,对新手不太友好。

JDK1.5之后出现了枚举,并且完美支持单例模式,并且线程安全、效率高!但是这些不是最重要的,最重要的是书写超级简单!究竟有多简单,看下面的示例应该就可以了解一下了。。。

枚举单例

 enum SingletonTest7{INSTANCE;}

对的,你没看错,就这点代码,其它不需要了。。。
枚举需要在JDK1.5之后的版本,它无偿提供序列化机制,绝对防止多次实例化,即使在面对复杂的序列化或者反射攻击的时候。这种方法也被Effective Java作者Josh Bloch 所提倡。

总结

单例模式的几种使用就到这了,那么我们来总结下使用单例模式需要注意什么(不包括枚举)。

  1. 构造方法私有化(private);
  2. 定义一个私有(private)静态(static)实例化对象;
  3. 对外提供一个公共(public)静态(static)的方法得到该实例;

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

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

相关文章

【数据分享】全国各省份农业-瓜果类面积(1993-2018年)

数据介绍 一级标题指标名称指标全称单位指标解释农业瓜果类面积农业-瓜果类面积-瓜果类面积千公顷根据第三次全国农业普查结果,对2007年-2017年农业生产有关数据进行了修正。农业西瓜面积农业-瓜果类面积-西瓜面积千公顷根据第三次全国农业普查结果,对2…

守护头顶安全——AI高空抛物监测,让悲剧不再重演

在城市的喧嚣中,我们享受着高楼林立带来的便捷与繁华,却往往忽视了那些隐藏在高空中的危险。近日,震惊全国的高空抛物死刑案件被最高院核准并执行。案件中被告人多次高空抛物的举动,夺去了无辜者的生命,也让自己付出了…

django5入门【03】新建一个hello界面

文章目录 1、前提条件⭐2、操作步骤总结3、实际操作示例 1、前提条件⭐ 将上一节创建的 Django 项目导入到 PyCharm 中。 2、操作步骤总结 (1)在 HelloDjango/HelloDjango 目录下,新建一个 views.py 文件。 (2)在 H…

解决运行jar错误: 缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序

报错 众所周知jdk8以上都没有Javafx java -jar target/myyscan-1.0-SNAPSHOT.jar 错误: 缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序解决 https://gluonhq.com/products/javafx/ 去下载/javafx/到本地,选择自己的型号 然后记得指定路径 java --m…

arcgis中dem转模型导入3dmax

文末分享素材 效果 1、准备数据 (1)DEM (2)DOM 2、打开arcscene软件 3、加载DEM、DOM数据 4、设置DOM的高度为DEM

yub‘s Algorithm exercise Day13

用栈实现队列 link:232. 用栈实现队列 - 力扣(LeetCode) 思路分析 首先理清楚栈和队列的异同. 队列是先进先出 栈先进后出【两者都能存储元素】 再来看peek()和poll(). 栈和队列都有peek() 可以称之为“瞄一眼”只是看一下当前栈顶/队头元…

基于vue框架的的高校消防设施管理系统06y99(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能:设备分类,设备信息,维修人员,报修信息,维修进度,院系,消防知识,培训记录,培训信息,备件信息,备件申请,派发信息,采购信息 开题报告内容 基于Vue框架的高校消防设施管理系统开题报告 一、项目背景与意义 随着高校规模的不断扩大和校园建…

61 mysql 存储引擎之动态格式 MyISAM

前言 我们这里来看一下 MyISAM 存储引擎, 我们常见的那些 user, db, table_priv, proc 等等是基于 MyISAM 这是我们经常会提及的 两种持久化的存储引擎之一, 一是 MyISAM存储引擎, 另外一个是 InnoDB存储引擎 我们这里来看一下 MyISAM 中动态长度的数据表的相关处理 mysql…

图片怎么转换成word文档?5种方法快速实现转换

不管是在学校学习还是在工作中,我们经常需要将图片中的文字转换成Word文档,以便于编辑和保存,但是很多小伙伴不知道该怎样转换,今天,就为大家介绍5种高效的图片转Word文档的方法,一起来学习下吧。 方法一&a…

IDEA设置JDK

IDEA设置JDK的前提是我们电脑中要下载安装了JDK 下面有JDK下载安装的详细教程 2024最新版JDK安装-CSDN博客文章浏览阅读3.4k次,点赞33次,收藏38次。安装JDK以及配置环境变量,检查是否安装成功_jdkhttps://blog.csdn.net/m0_61840987/articl…

威胁 Windows 和 Linux 系统的新型跨平台勒索软件:Cicada3301

近年来,网络犯罪世界出现了新的、日益复杂的威胁,能够影响广泛的目标。 这一领域最令人担忧的新功能之一是Cicada3301勒索软件,最近由几位网络安全专家进行了分析。他们有机会采访了这一危险威胁背后的勒索软件团伙的成员。 Cicada3301的崛…

笔记本电脑充不进去电怎么回事 笔记本电脑充不上电解决

当你满心欢喜地准备使用笔记本电脑,却突然发现它充不进去电,这无疑会让人感到十分困扰。究竟是什么原因导致了这一问题的出现呢?别着急,让我们一起来探寻笔记本电脑充不进去电的奥秘,并找到相应的解决办法。 一、原因…

批量修改YOLO格式的标注类别

1.解决的问题 假如你有一个YOLO格式的数据集,标注类别为0,1,2,3四个类别标签。如果你想删除标签1,只保留0,2,3类别的标注信息,或者想将标签0和标签1合并为标签1,只剩下标…

【Vulnhub靶场】DC-2

DC-2 靶场下载地址:https://download.vulnhub.com/dc/DC-2.zip 目标 本机IP:192.168.118.128 靶机IP:192.168.118.0/24 信息收集 常规我使用nmap三扫描,扫存活主机、扫端口、扫服务 第一步探测到存活主机IP为:192.1…

虚拟机网络设置为桥接模式

1、打开VMware Workstation Pro,点击“虚拟机—设置”,进入虚拟机设置页面 2、点击“网络适配器”,网络连接选择桥接模式 3、点击“编辑—虚拟网络编辑器”,进入虚拟网络编辑器页面 4、选择桥接模式,并选择要桥接到的…

Docker 部署 EMQX 一分钟极速部署

部署 EMQX ( Docker ) [Step 1] : 拉取 EMQX 镜像 docker pull emqx/emqx:latest[Step 2] : 创建目录 ➡️ 创建容器 ➡️ 拷贝文件 ➡️ 授权文件 ➡️ 删除容器 # 创建目录 mkdir -p /data/emqx/{etc,data,log}# 创建容器 docker run -d --name emqx -p 1883:1883 -p 1808…

内网穿透:如何借助Cloudflare连接没有公网的电脑的远程桌面(RDP)

内网穿透:如何借助Cloudflare连接没有公网的电脑的远程桌面(RDP)-含详细原理配置说明介绍 前言 远程桌面协议(RDP, Remote Desktop Protocol)可用于远程桌面连接,Windows系统(家庭版除外)也是支持这种协议的,无需安装…

代理与 Hubstudio 集成

文章目录 一、什么是 Hubstudio?二、为什么是动态住宅代理?三、使用 Hubstudio 设置 Smartdaili 代理3.1. 与动态住宅代理的整合 3.2. 使用 Hubstudio 设置代理 总结 将 Smartdaili 动态住宅代理与 Hubstudio 反检测浏览器配对使用,即可轻松管理多个账户…

npm、yarn、pnpm的workspaces使用

示例项目中总会遇到npm的packages中出现的workspaces键值对,自己的项目中没接触过这个东西,到底是什么?怎么用的?简单研究记录一下: abbrev是一个npm包,提供缩写展开功能。‌ 当你定义一个缩写后&#xff0…

设计一个html+css+js的注册页,对于注册信息进行合法性检测

综合使用HTML、JavaScript和CSS进行注册页面设计,实现以下若干功能: 注意整个页面的色调和美观使用FramesetTable布局(div也可)对用户ID和用户名、口令不符合条件及时判断对口令不一致进行及时判断(34的及时判断&#…