工厂模式和单例模式

news2024/12/30 3:00:16

目录

一.设计模式

二.工厂模式和单例模式

🐞单例模式

1.饿汉模式 

2.懒汉模式

(1)问题一:大量对象的创建

(2)问题二:加锁导致阻塞等待

(3)问题三:指令重排序

🐞工厂模式

 三.总结分析


一.设计模式

设计模式

设计模式是一种被广泛接受和验证的解决问题的经验总结,它提供了一套通用的解决方案,帮助开发人员解决常见的设计问题。使用设计模式可以提高代码的可读性、可维护性和可扩展性,减少代码的重复性,提高开发效率。🤗

学习设计模式的意义主要体现在以下几个方面:

  1. 提高设计能力:学习设计模式可以帮助开发人员理解和掌握各种设计原则和设计思想,提高设计能力,能够更好地进行系统设计和架构设计。

  2. 代码重用和维护:设计模式提供了一套通用的解决方案,可以避免重复造轮子,提高代码的重用性。同时,设计模式的使用也能够提高代码的可读性和可维护性,使代码更易于理解和修改。

  3. 提高团队合作效率:设计模式是一种标准化的解决方案,团队成员之间可以通过共享和理解设计模式来进行沟通和合作,提高团队的合作效率。

  4. 更好地理解和应用框架:许多框架和库都使用了设计模式,学习设计模式可以帮助开发人员更好地理解和应用这些框架,提高开发效率。

我们今天来详细了解面试常考的工厂模式和单例模式👀

二.工厂模式和单例模式

🐞单例模式

单例,顾名思义,也就是单个实例(instance),类的实例,就是对象

单例,也就是在一个程序中的某个类,只创建出一个实例(一个对象),不能创建多个对象

⌛有的人可能会想,那我多new几次,不就创建出多个对象了吗?🤔

但是语法上是有办法禁止让你这样多new的.

Java中的单例模式,实际上就是借助Java语法,保证某个类,只能够创建出一个实例,而不能多次"new"

⌛那么单例模式用途是什么呢?

Java中的有些场景,本身就是要求某个概念是单例的

比如只能有一个太阳,一个人只能有一个妻子.

接下来,我们看看在Java中如何实现单例模式.🤗

实际上,Java中实现单例模式有很多种写法,我们主要来学习这两种:

  • 饿汉模式 
  • 懒汉模式

 我们来看这段代码:

class  Singleton{
    //唯一实例的本体
    private static  Singleton instance =new Singleton();

    //获取实例的方法
    public static Singleton getInstance(){
        return instance;
    }
    //禁止外部new对象
    private Singleton(){

    }
}

public class ThreadDemo17 {
    public static void main(String[] args) {
        //此时s1和s2调用得到的是同一个对象
        Singleton s1=Singleton.getInstance();
        Singleton s2=Singleton.getInstance();

        //Singleton s3=new Singleton();
    }
}

我们来具体分析这段代码:

📢饿汉模式,突出一个词是"急迫"

📢懒汉模式,形容起来就是"从容"

具体是怎么回事呢?我们来进行详细介绍

懒汉模式来实现单例.主要的核心思想就是非必要,不创建

而饿汉就是提前创建好,直接可以使用

1.饿汉模式 

代码如下:

//饿汉模式
class  Singleton{
    //唯一实例的本体
    private static  Singleton instance =new Singleton();

    //获取实例的方法
    public static Singleton getInstance(){

        return instance;
    }

    //禁止外部new对象
    private Singleton(){

    }
}

2.懒汉模式

//懒汉模式
class SingletonLazy{
    public static SingletonLazy instance=null;
    public static SingletonLazy getInstance(){
        if(instance==null){
            instance=new SingletonLazy();
        }
        return instance;
    }
    private SingletonLazy(){
        
    }
}

上面的代码并不难,但是有几个重要问题:

⌛以上两个代码,是否是线程安全的?

⌛多个线程下调用getInstance,是否会出现问题?

⌛代码中加上了synchorized,是为什么呢?

饿汉模式认为线程是安全的,因为只是读数据

但是懒汉模式在多线程下,却无法保证创建对象的唯一性.

(1)问题一:大量对象的创建

我们可以看到,懒汉模式需要进行判空,那么如果在空对象条件下突然有多个线程进行调用,就有可能创建出多个对象,这个时候就有可能会出现问题了.

这是因为对象有大有小,有些对象管理的内存数据可能会有很多,如果同时调用创建出这么多对象,线程就有可能会崩溃了.

所以,我们如何解决上述问题呢?办法就是加锁.

代码如下:

//懒汉模式
class SingletonLazy{
    public static SingletonLazy instance=null;
    public static SingletonLazy getInstance(){
        if(instance==null){
            synchronized (SingletonLazy.class){
                instance=new SingletonLazy();
            }
        }
        return instance;
    }
    private SingletonLazy(){

    }
}

这样加上锁之后就能保证判定和new是一个原子操作,这样就可以避免同时创建出大量对象了.

(2)问题二:加锁导致阻塞等待

然而,加锁是一个比较低效的操作,因为加锁了就可能涉及到阻塞等待,所以我们的原则是非必要不加锁,那么,还有什么更好的办法吗?

我们可以修改代码形式以达到避免阻塞等待的目的。

我们来看看这个代码:

class SingletonLazy{
    private static SingletonLazy instance=null;
    public static SingletonLazy getInstance(){
        if(instance==null){
            synchronized (SingletonLazy.class){
                if(instance==null){
                    instance=new SingletonLazy();
                }
            }
        }

        return instance;
    }

    private SingletonLazy(){

    }
}

我们来对代码进行分析:

(3)问题三:指令重排序

但是,事情到这里就结束了吗?

上述代码其实还面临着一个很重要的问题——指令重排序

 那么,这个问题如何来解决呢?

我们可以通过添加volatile来禁止指令重排序

具体代码如下:

class SingletonLazy{
    volatile private static SingletonLazy instance=null;
    public static SingletonLazy getInstance(){
        if(instance==null){
            synchronized (SingletonLazy.class){
                if(instance==null){
                    instance=new SingletonLazy();
                }
            }
        }

        return instance;
    }

    private SingletonLazy(){

    }
}

这样,就可以有效解决上述问题了

我们现在可以来总结一下了

单例模式具有线程安全问题

懒汉模式:天然就是安全的,只是读操作

饿汉模式:不安全,有读和写操作

解决方法:1.加锁,把if和new变成原子操作

                2.双重if,减少不必要的加锁操作

                3.使用volatile禁止指令指令重排序,保证后续线程拿到的是完整对象.

🐞工厂模式

工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们创建对象而不是直接通过 new 关键字来创建,而是使用一些其他的方法(通常是静态方法)帮助我们把对象创建出来.

工厂模式,实际上是用来填构造方法的坑的.因为构造方法如果想要提供多种不同的构造对象的方法,就得基于重载.

比如说我们想描述平面上的一个点,就有很大的问题.

 这个时候,我们就可以通过构造一个工厂类来解决.

代码如下:

public class PointBuilder {
    // 根据坐标创建 Point 对象
    public static Point makePointByXY(double x, double y) {
        return new Point(x, y);
    }
    
    // 根据极坐标创建 Point 对象
    public static Point makePointByRA(double r, double a) {
        double x = r * Math.cos(a);
        double y = r * Math.sin(a);
        return new Point(x, y);
    }
}

在上面的代码中,我们定义了一个工厂类 PointBuilder,其中包含了两个静态方法 makePointByXY 和 makePointByRA。这两个方法分别根据坐标和极坐标创建 Point 对象。

📢makePointByXY 方法接收两个参数 x 和 y,直接使用这两个参数创建一个 Point 对象并返回。

📢makePointByRA 方法接收两个参数 r 和 a,根据极坐标的公式 x = r * cos(a) 和 y = r * sin(a) 计算出 x 和 y 的值,然后使用这两个值创建一个 Point 对象并返回。

这样,调用者可以直接通过 PointFactory 类来创建 Point 对象,而不需要关心对象的创建细节。调用者可以根据需要选择使用哪个方法来创建对象。

 三.总结分析

单例模式和工厂模式是两种常见的设计模式,它们在软件开发中具有不同的作用和应用场景。

  • 单例模式用于确保一个类只有一个实例存在,并提供全局访问点。它适用于需要全局共享某个对象的场景,例如资源池、配置信息等。

  • 工厂模式用于封装对象的创建过程,将对象的实例化和使用解耦。它适用于需要根据不同的条件创建不同的对象的场景,提供灵活性和可扩展性。

 在以后的学习中,应根据具体的需求和设计目标选择适合的设计模式..🤗

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

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

相关文章

MySql进阶篇---006:存储引擎,索引,SQL优化,视图、存储过程、变量、流程控制、游标、存储函数、触发器

1. 存储引擎 1.1 MySQL体系结构 1).连接层 最上层是一些客户端和链接服务,包含本地sock 通信和大多数基于客户端/服务端工具实现的类似于TCP/IP的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念,为通过认证…

【面试经典150 | 矩阵】螺旋矩阵

文章目录 写在前面Tag题目来源题目解读解题思路方法一:模拟方法二:按层模拟 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更…… 专栏内容以分析题目为主,并附带一些对于…

04. Springboot集成Mybatis-flex(二)

1、前言 上一篇文章《Springboot集成Mybatis-flex(一)》提到Mybatis Flex和Spring Boot的初步集成和基础使用。今天我们再来探索Mybatis Flex其他特性的使用。 2、数据填充 数据填充指的是,当 Entity 数据被插入 或者 更新的时候&#xff…

Ghostscript 字体处理深究: 解决字体缺失问题

🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…

Hello World!1分钟配置好你的Go环境

目录 一、简介为什么选择Golang?Golang与其他语言的对比核心特性应用场景社区和生态系统性能标准企业级应用 二、环境要求操作系统WindowsLinux/UnixmacOS 硬件需求其他依赖软件异常情况和处理方法 三、下载和安装GolangWindows系统使用官方安装包使用Chocolatey&am…

使用CreateProcess崩溃:处未处理的异常: 0xC0000005: 写入位置 0x00415652 时发生访问冲突

问题代码 if (!CreateProcess(NULL,L"pela.exe",NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi)){return 0;}如果CreateProcess的第二个参数字符串是常量或者是储存在堆中的就会被写保护,崩溃。如果字符串定义到栈或者全局变量就不存在此问题了。 正确的…

初级篇—第二章SELECT查询语句

文章目录 什么是SQLSQL 分类SQL语言的规则与规范阿里巴巴MySQL命名规范数据导入指令 显示表结构 DESC基本的SELECT语句SELECTSELECT ... FROM列的别名 AS去除重复行 DISTINCT空值参与运算着重号查询常数过滤数据 WHERE练习 运算符算术运算符加减符号乘除符号取模符号 符号比较运…

SNERT预备队招新CTF体验赛-Misc(SWCTF)

目录 1、最简单的隐写 2、旋转我 3、is_here 4、zip伪加密 5、压缩包密码爆破 6、我就藏在照片里 7、所以我放弃了bk 8、套娃 9、来自银河的信号 10、Track_Me 11、勇师傅的奇思妙想 1、最简单的隐写 下载附件后,图片格式并不支持打开 根据题目提示&…

Window 安装多个版本的 java 并按需切换

1、按需下载对应版本的 java 官网链接:Java Downloads | Oracle 2、执行安装程序,根据安装向导一步一步走就行,每个版本安装在不同的目录下。 3、配置环境变量 a)为每个版本 java 新建不同名称的 JAVA_HOME 系统变量&#xff0…

最优化:建模、算法与理论(最优性理论

第五章 最优性理论 在实际中最优化问题的形式多种多样,给定一类具体的优化问题,我们首先需要分析其解的存在性。如果优化问题的解存在,再考虑如何设计算法求出最优解,一般的非凸优化问题可能存在很多局部极小解,但其往…

使用WPS自动化转换办公文档: 将Word, PowerPoint和Excel文件转换为PDF

🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…

IDEA-2023-jdk8 HelloWorld的实现

目录 1 新建Project - Class 2 编写代码 3 运行 1 新建Project - Class 选择"New Project": 指名工程名、使用的JDK版本等信息。如下所示: 接着创建Java类: 2 编写代码 public class HelloWorld {public static void main(S…

桂院校园导航 | 云上高校导航 云开发项目 二次开发教程 1.2

Gitee代码仓库:桂院校园导航小程序 GitHub代码仓库:GLU-Campus-Guide 演示视频 【2023广西赛区 | 三等奖】中国大学生计算机设计大赛 云上高校导航 先 假装 大伙都成功安装了云开发项目,并能在 微信开发者工具 和 手机 上正确运行。 接着就…

【生物信息学】使用HSIC LASSO方法进行特征选择

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 3. IDE 三、实验内容 0. 导入必要的工具 1. 读取数据 2. 划分训练集和测试集 3. 进行HSIC LASSO特征选择 4. 特征提取 5. 使用随机森林进行分类(使用所有特征) 6. 使用随机森…

【面试经典150 | 矩阵】有效的数独

文章目录 写在前面Tag题目来源题目解读解题思路方法一:一次遍历数组 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更…… 专栏内容以分析题目为主,并附带一些对于本题涉及到的数据结…

电脑通过串口助手和51单片机串口通讯

今天有时间把电脑和51单片机之间的串口通讯搞定了,电脑发送的串口数据,单片机能够正常接收并显示到oled屏幕上,特此记录一下,防止后面自己忘记了怎么搞得了。 先来两个图片看看结果吧! 下面是串口3.c的文件全部内容&a…

python爬取百度图片

1.查询数据 打开网页。 https://cn.bing.com/images/search?q%E7%99%BE%E5%BA%A6%E5%9B%BE%E7%89%87&formHDRSC2&first1&cw1585&ch924 我们右键查看网页源代码,发现能找到我们需要的img衔接,但是这是一个动态网页。我们每次向下滑动网页,会发现图…

基于Java的医院预约挂号系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后福利 代码参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

uboot启动流程-涉及lowlevel_init汇编函数

一. uboot启动流程涉及函数 之前文章简单分析了 uboot启动流程的开始,从链接脚本文件 u-boot.lds 中,我们已经知道了入口点是 arch/arm/lib/vectors.S 文件中的 _start函数。 _start函数:调用了 reset 函数,reset 函数内部&…

【小沐学前端】Node.js实现基于Protobuf协议的UDP通信(UDP/TCP/WebSocket)

文章目录 1、简介1.1 node1.2 Protobuf 2、下载和安装2.1 node2.2 Protobuf2.2.1 安装2.2.2 工具 3、node 代码示例3.1 HTTP3.2 UDP单播3.4 UDP广播 4、Protobuf 代码示例4.1 例子: awesome.proto4.1.1 加载.proto文件方式4.1.2 加载.json文件方式4.1.3 加载.js文件方式 4.2 例…