小侃设计模式(二)-单例模式

news2024/11/16 15:33:12

1.概述

设计模式在粒度和抽象层次上各不相同,因此从不同的角度,分类形式也不同,目前存在两种较为经典的划分方式,即根据模式作用的范围、模式的目的来划分。根据模式主要是用于类还是用于对象,可将其划分为类模式和对象模式。类模式用于处理类与子类之间的关系,这些关系通过继承建立,体现了静态性。对象模式用于处理对象之间的关系,在运行时刻可以发生变化,体现了动态性。在某种程度上来说,继承机制几乎被所有模式使用,大多数模式都属于对象模式,小部分属于类模式。根据模式目的可将模式分为创建型模式、结构型模式和行为型模式。本文主要讲解创建型模式的单例模式。

2.单例模式

2.1 设计模式分类

1.创建型模式
创建型模式又分为创建型类模式和创建型对象模式,创建型类模式将对象的部分创建工作延迟到子类,创建型对象模式则将它延迟到另一个对象中。
2.结构型模式
结构型模式主要用于处理类和对象的组合,结构型类模式使用继承机制来组合类,结构型对象描述则描述了对象的组装方式。
3.行为型模式
行为型模式描述了类或对象之间的交互或职责分配,行为型类模式使用继承描述算法或控制流,行为型对象模式描述了一组对象怎样协作完成单个对象无法完成的任务。

在这里插入图片描述

2.2 单例模式

定义:采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个方法来保证其取得对象实例。单例模式共有8种,如下:
(1)饿汉式(静态常量)
(2)饿汉式(静态代码块)
(3)懒汉式(线程不安全)
(4)懒汉式(线程安全,同步方法)
(5)懒汉式(线程安全,同步代码块)
(6)双重检查
(7)静态内部类
(8)枚举

2.2.1 饿汉式(静态常量)

public class SigletonStatic {

    private SigletonStatic() {
    }

    private static final SigletonStatic INSTANCE = new SigletonStatic();

    public static SigletonStatic getInstance() {
        return INSTANCE;
    }
}

优势: 写法比较简单,在类装载的时候就完成了对象的实例化,避免了线程同步问题;
缺点:在类装载的时候就完成了对象的实例化,没有达到懒加载的效果,如果一直没有使用这个对象实例,则会造成内存浪费。
结论:这种单例模式可用,但是可能会造成内存浪费。

2.2.2 饿汉式(静态代码块)

public class SigletonStatic {

    private SigletonStatic() {
    }

    private static final SigletonStatic INSTANCE;

    static {
        INSTANCE = new SigletonStatic();
    }

    public static SigletonStatic getInstance() {
        return INSTANCE;
    }
}

优势: 写法比较简单,在类装载的时候就完成了对象的实例化,避免了线程同步问题;
缺点:在类装载的时候就完成了对象的实例化,没有达到懒加载的效果,如果一直没有使用这个对象实例,则会造成内存浪费。
结论:这种单例模式可用,但是可能会造成内存浪费。

这种写法和2.2.1节方式基本一致,唯一区别在于将对象的实例化放在了静态代码块中,所有基本优缺点是一致的。

2.2.3 懒汉式(线程不安全)

public class SigletonStatic {

    private SigletonStatic() {
    }

    private static SigletonStatic INSTANCE;

    public static SigletonStatic getInstance() {
    //判断INSTANCE是否为空,为空再创建
        if (INSTANCE == null) {
            INSTANCE = new SigletonStatic();
        }
        return INSTANCE;
    }

}

优点:实现了懒加载的效果,但是只能在单线程情况下使用;
缺点:在多线程情况下,可能存在线程安全问题,当前一个线程进入if (INSTANCE == null)语句得出结果为true时,还未来得及执行创建对象的代码,另一个线程也通过了这段代码,导致生成了多个对象实例。
结论:多线程情况下,不建议使用。

2.2.4 懒汉式(线程安全,同步方法)

public class SigletonStatic {

    private SigletonStatic() {
    }

    private static SigletonStatic INSTANCE;
    
    //加入同步处理代码块,解决线程安全问题
    public static synchronized SigletonStatic getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new SigletonStatic();
        }
        return INSTANCE;
    }

}

优势: 解决了懒加载和线程安全问题;
缺点:效率较低,每次来获取INSTANCE对象时,都需要加锁,但其实只是第一次创建对象时需要加锁。
结论:效率较低,不建议使用。

2.2.5 懒汉式(线程安全,同步代码块)

public class SigletonStatic {

    private SigletonStatic() {
    }

    private static SigletonStatic INSTANCE;

    public static SigletonStatic getInstance() {
        if (INSTANCE == null) {
            synchronized (SigletonStatic.class) {
                INSTANCE = new SigletonStatic();
            }
        }
        return INSTANCE;
    }

}

优势:这种方式本意是为了改良2.2.4种的方法,有一定的效率提示;
缺点: 并不能完全解决线程安全问题,与2.2.3节类似,可能存在创建多个对象实例;
结论:不够安全,不建议使用。

2.2.6 双重检查

public class SigletonStatic {

    private SigletonStatic() {
    }
	//volatile修饰,保证线程之间可见性
    private static volatile SigletonStatic INSTANCE;

    public static SigletonStatic getInstance() {
        if (INSTANCE == null) {
            synchronized (SigletonStatic.class) {
            //二次校验,保证对象只创建一次
                if (INSTANCE == null) {
                    INSTANCE = new SigletonStatic();
                }
            }
        }
        return INSTANCE;
    }

}

优势:保证了INSTANCE只被实例化了一次,同时保证了线程安全,保证了延时加载,效率较高;
缺点:相对完美的方案;
结论:建议开发中使用。

2.2.7 静态内部类

public class SigletonStatic {
    private SigletonStatic() {
    }
    
    //写一个静态内部类,类中包含属性SigletonStatic
    private static class SigletonInstance {
        private static final SigletonStatic INSTANCE = new SigletonStatic();
    }
    //提供一个静态的公有方法
    public static SigletonStatic getInstance() {
        return SigletonInstance.INSTANCE;
    }
}

优势:这种方式采用了类加载的机制来保证初始化时只有一个线程,静态内部类SigletonInstance在SigletonStatic 被加载时不会立即被实例化,而是在调用getInstance()方法时才会被装载,从而创建INSTANCE 对象;类的静态属性INSTANCE 只会在第一次被装载时实例化,因此JVM帮我们保证了线程安全,在类SigletonInstance初始化时,别的线程无法进入;避免了线程不安全,利用静态内部类实现了延时加载;
结论:建议开发中使用。

2.2.8 枚举

enum SigletonStatic {
    INSTANCE;
    
    private void method() {
        System.out.println("method done!");
    }  
}

优势:借助于枚举来实现单例模式,不仅避免了多线程的同步问题,还能防止反序列化重新创建新的对象。
结论:建议开发中使用。

3.小结

1.单例模式的创建主要包括懒汉式和饿汉式,饿汉式是类加载时就进行对象实例化,懒汉式是使用时才创建对象;
2.饿汉式可能出现对象提前创建而未使用,导致资源浪费的情况;
3.懒汉式可能存在线程安全问题,因此建议使用双重检查、静态内部类、枚举等方式来创建单例对象。

4.参考文献

1.《设计模式-可复用面向对象软件的基础》-Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides
2.《可复用物联网Web3D框架的设计与实现》-程亮(知网)
3.https://www.bilibili.com/video/BV1G4411c7N4-尚硅谷设计模式

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

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

相关文章

【JavaWeb】Tomcat

1.JavaWeb是指所有通过java语言编写可以通过浏览器访问的程序的总称 请求是指客户端给服务器发送数据 响应是指服务器给客户端回传数据 2.Web资源按实现的技术和呈现的效果的不同,又分为静态资源和动态资源两种. 静态资源:html css js txt mp4视频 jpg图片 动态资源:jsp页面 se…

前端工程化基建探索:从内部机制和核心原理了解npm

大厂技术 坚持周更 精选好文 前言 本文【前端工程化基建探索】的第2篇,上一篇 前端工程化基建探索(1)前端大佬,你好! 当我们拉取一个前端工程化项目,都会通过npm/Yarn/pnpm 管理工具来安装项目的依赖&am…

大学解惑06 - 要求输入框内只能输入2位以内小数,怎么做?

请听题:有一个输入框,准备用于计算使用,要求点击“校验”按钮的时候进行验证,必须输入数字,并且只能是2位以内的小数,如果输入不合法,请给出提示,如果输入合法通过验证,则…

又是一篇教你摸鱼的文章,用Python实现自动发送周报给老板

前言 有没有哪个同志跟我一样,每周都要写工作周报 像我这种记性不好的,一个月四周忘记三次 索性就用Python写个小工具,让它每周帮我给老板发周报~ Github: Weekday 小工具 提出目标 源码.资料.素材.点击领取即可 想有一个工具能发邮件 目…

ARM 汇编基础

一、ARM架构 ARM芯片属于精简指令集计算机(RISC:Reduced Instruction Set Computing),它所用的指令比较简单,有如下特点: 对内存只有读、写指令对于数据的运算是在CPU内部实现使用RISC指令的CPU复杂度小一点,易于设计…

WebShell箱子简介与原理

今天继续给大家介绍渗透测试相关知识,本文主要内容是WebShell箱子简介与原理。 免责声明: 本文所介绍的内容仅做学习交流使用,严禁利用文中技术进行非法行为,否则造成一切严重后果自负! 再次强调:严禁对未授…

【面试】【项目】谷粒商城

视频链接 项目调查 这项目是这么多免费视频里最好的了。但依旧是demo。 最好还是买慕课网上的实战课,那些老师都有丰富的开发经验,有经验跟没经验讲的课是完全不同的。 谷粒商城我觉得是不low的,我很菜,毕业一年半被多次辞退&a…

数据结构之-【排序】

目录 排序 ⚡️冒泡排序 ⚡️选择排序 ⚡️插入排序 ⚡️堆排序 ⚡️归并排序 ⚡️快速排序 🏳️‍🌈排序 将数字从小到大的顺序排列 🔴冒泡排序 「冒泡排序」重复"从序列右边开始比较相邻两个数字的大小,再根据结果交换两个…

国产蓝牙耳机哪个牌子好?国产蓝牙耳机质量排行榜

随着3.5 mm耳机插孔被淘汰,特别是5G时代,让手机的内部结构变得越来越小,要将耳机插口塞进一个新的插口,无疑是一件非常困难的事情,而随着蓝牙技术的不断进步,蓝牙耳机也逐渐成为了如今人们配戴手机的首选&a…

Revit中阀门在项目中不可用无法与管道连接?

一、Revit中阀门在项目中不可用的问题 在项目中放置阀门时,有时候不可用,会出现如图1所示问题,无法与管道连接。 出现上图显示问题是因为在编辑族的时候,阀门两边的连接件原心没有完全重合。打开编辑族界面,可以看到如…

怎么辨别哪些才是真的低代码开发平台?

怎么辨别哪些才是真的低代码开发平台?第一次看到这个问题时,我就知道为什么有人会这么问了,目前低代码市场龙蛇混杂,普通人很难分辨出“真”低代码。所以这个问题中“真正”二字最为重要,圈起来,下面我们正…

【产品新体验】CSDN开发云·云IDE使用教程

【产品新体验】CSDN开发云云IDE使用教程1、初识云IDE1.1 拉去git项目1.2 密钥管理2、整体分析云IDE产品介绍 云IDE使用教程 免费使用地址:点击【云IDE】,即可开始创建工作空间啦~ CSDN最新产品【云IDE】来啦!【云IDE】将为各位技术er一键秒级…

No6-3.从零搭建spring-cloud-alibaba微服务框架,实现资源端用户认证与授权等(三,no6-3)

代码地址与接口看总目录:【学习笔记】记录冷冷-pig项目的学习过程,大概包括Authorization Server、springcloud、Mybatis Plus~~~_清晨敲代码的博客-CSDN博客 之前只零碎的学习过spring-cloud-alibaba,并没有全面了解过,这次学习p…

【Python】入门,总结与拾遗

前言 根据我的实践经验来看,对于有编程基础(如C语言)的同学来说,python入门应该很简单,而且加上官方文档做得非常好,所以个人建议python的学习主要去参考官网。本博客主要是记录那些容易忽略的关键点以及对…

蓝桥杯单片机第七届省赛题详细讲解(温度记录器)

看之前强烈建议先自己做一遍!!!演示效果题目讲解代码main.cds1302.cds1302.honewire.conewire.h工程文件演示效果 题目讲解 首先我们从系统框图看起: 做题之前要做的是把系统框图里面的各个模块先提前调试好!&#x…

StarRocks 的学习笔记

StarRocks 的学习笔记 文章目录StarRocks 的学习笔记1. 介绍1.1 StarRocks 特性1.2 使用场景1.3 OLAP 多维分析1.4 实时数据仓库1.5 高并发查询1.6 统一分析2. 系统架构2.1 StarRocks架构2.2 StarRocks业务架构2.3 StarRocks 数据生态2.4 *数据管理3. 特性3.1 MPP分布式执行框架…

ES6中的set与map

文章目录1.set1.1创建set集合1.2 如何对set集合进行后续操作1.3 如何与数组进行相互转换1.4 如何遍历1.5set的应用2.map集合2.1 如何创建map2.2 如何进行后续操作2.3 如何与数组转换2.4 遍历一直以来,JS只能使用数组和对象来保存多个数据,缺乏像其他语言…

介绍document部分自带的方法及属性,场景使用例如倒计时等

适用场景页面不显示(不看)触发方法停止运行逻辑,页面显示(看)触发方法继续运行逻辑。 (例如倒计时) 操作手法触发,浏览器多页签切换时触发,或者当前页隐藏浏览器&#xf…

飞象星球落地舟山36所学校 双师课堂化解课后服务区域资源差异

傍晚的阳光正好,此时舟山二小北校区五年级学生周陈延正紧盯大屏幕,沉醉在《航天探秘》飞象星球双师素质课堂带来的知识奥义中。作为浙江极具特色的海岛城市,舟山正进行着有关课后服务领域的新探索,双师素质课堂便是“千岛之城”舟…

VSCODE联合ModelSim语法检错

Vscode联合ModelSim检错 一、Vscode配置 首先在 vs code 中安装支持 Verilog 的插件: 在 vs code 的 Extension 中搜索 Verilog,安装如下图所示的插件; 二、ModelSim语法检查器检查 Modelsim的安装破解本文不再赘述,可选的Mod…