当前位置: 首页 > news >正文

Java面试题--设计模式

一、Java 中有几种设计模式?

Java 中一般认为有 23 种设计模式

分为三大类:

1. 创建型模式 5 种

① 工厂方法模式

② 抽象工厂模式

③ 单例模式

④ 建造者模式

⑤ 原型模式

2. 结构型模式 7 种

① 适配器模式

② 装饰器模式

③ 代理模式

④ 外观模式

⑤ 桥接模式

⑥ 组合模式

⑦ 享元模式

3. 行为型模式 11 种

① 策略模式

② 模板方法模式

③ 观察者模式

④ 迭代子模式

⑤ 责任链模式

⑥ 命令模式

⑦ 备忘录模式

⑧ 状态模式

⑨ 访问者模式

⑩ 中介者模式

⑪ 解释器模式

 二、什么是单例设计模式?

1. 单例模式定义

单例模式确保某个类只有一个实例,而

且自行实例化并向整个系统提供这个实

在计算机系统中,线程池、缓存、日志

对象、对话框、打印机、显卡的驱动程

序对象常被设计成单例,选择单例模式

就是为了避免不一致状态

2. 单例模式的特点

① 单例类只能有一个实例

② 单例类必须自己创建自己的唯一实例

③ 单例类必须给所有其他对象提供这一

    实例

④ 单例模式保证了全局对象的唯一性

    比如系统启动读取配置文件就需要单

    例保证配置的一致性

3. 单例的四大原则

① 构造器私有化

② 以静态方法或者枚举返回实例

③ 确保实例只有一个,尤其是多线程

    环境

④ 确保反序列化时不会重新构建对象

4.  实现单例模式的方式

(1) 饿汉式 (立即加载):

饿汉式单例在类加载初始化时就创建

一个静态的对象供外部使用,除非系统

重启,这个对象不会改变,所以本身就

是线程安全的

Singleton 通过将构造方法限定为 private

避免了类在外部被实例化,在同一个虚拟

机范围内,Singleton 的唯一实例只能通

过 getInstance() 方法访问 (事实上,通过

Java 反射机制是能够实例化构造方法为

private 的类的,会使 Java 单例实现失效)

/*** 饿汉式(立即加载)*/
public class Singleton1 {/*** 私有构造*/private Singleton1() {System.out.println("构造函数Singleton1");}/*** 初始值为实例对象*/private static Singleton1 single = new Singleton1();/*** 静态工厂方法* @return 单例对象*/public static Singleton1 getInstance() {System.out.println("getInstance");return single;}public static void main(String[] args){System.out.println("初始化");Singleton1 instance = Singleton1.getInstance();}
}
(2) 懒汉式 (延迟加载):

该示例虽然用延迟加载方式实现了懒汉

式单例,但在多线程环境下会产生多个

Singleton 对象


/*** 懒汉式(延迟加载)*/
public class Singleton2 {/*** 私有构造*/private Singleton2() {System.out.println("构造函数Singleton2");}/*** 初始值为null*/private static Singleton2 single = null;/*** 静态工厂方法* @return 单例对象*/public static Singleton2 getInstance() {if(single == null){System.out.println("getInstance");single = new Singleton2();}return single;}public static void main(String[] args){System.out.println("初始化");Singleton2 instance = Singleton2.getInstance();}
}
(3) 同步锁 (解决线程安全问题):

在方法上加 synchronized 同步锁或是

用同步代码块对类加同步锁,此种方

式虽然解决了多个实例对象问题,但

是该方式运行效率却很低下,下一个

线程想要获取对象,就必须等待上一

个线程释放锁之后,才可以继续运行

/**** 同步锁(解决线程安全问题)*/
public class Singleton3 {/*** 私有构造*/private Singleton3() {}/*** 初始值为null*/private static Singleton3 single = null;public static Singleton3 getInstance() {// 等同于 synchronized public static Singleton3 getInstance()synchronized(Singleton3.class){// 注意:里面的判断是一定要加的,否则出现线程安全问题if(single == null){single = new Singleton3();}}return single;}
}
(4) 双重检查锁 (提高同步锁的效率):

使用双重检查锁进一步做了优化,可

以避免整个方法被锁,只对需要锁的

代码部分加锁,可以提高执行效率

/*** 双重检查锁(提高同步锁的效率)*/
public class Singleton4 {/*** 私有构造*/private Singleton4() {}/*** 初始值为null*/private static Singleton4 single = null;/*** 双重检查锁* @return 单例对象*/public static Singleton4 getInstance() {if (single == null) {synchronized (Singleton4.class) {if (single == null) {single = new Singleton4();}}}return single;}
}
(5) 静态内部类:

引入了一个内部静态类 (static class),静

态内部类只有在调用时才会加载,它保证

了 Singleton 实例的延迟初始化,又保证

了实例的唯一性

它把 singleton 的实例化操作放到一个静

态内部类中,在第一次调用 getInstance()

方法时,JVM 才会去加载 InnerObject 类,

同时初始化 singleton 实例,所以能让

getInstance() 方法线程安全

   特点:即能延迟加载,也能保证线程安全

静态内部类虽然保证了单例在多线程并发

下的线程安全性,但是在遇到序列化对象

时,默认的方式运行得到的结果就是多例

/**** 静态内部类(延迟加载,线程安全)*/
public class Singleton5 {/*** 私有构造*/private Singleton5() {}/*** 静态内部类*/private static class InnerObject{private static Singleton5 single = new Singleton5();}public static Singleton5 getInstance() {return InnerObject.single;}
}
(6) 内部枚举类实现 (防止反射攻击):

事实上,通过 Java 反射机制是能够实例

化构造方法为 private 的类的,这也就是

我们现在需要引入的枚举单例模式

public class SingletonFactory {/*** 内部枚举类*/private enum EnumSingleton{Singleton;private Singleton6 singleton;//枚举类的构造方法在类加载是被实例化private EnumSingleton(){singleton = new Singleton6();}public Singleton6 getInstance(){return singleton;}}public static Singleton6 getInstance() {return EnumSingleton.Singleton.getInstance();}
}class Singleton6 {public Singleton6(){}
}

三、什么是工厂设计模式?

工厂设计模式就是用来生产对象的,在

java 中,万物皆对象,这些对象都需要

创建,如果创建的时候直接 new 该对象,

就会对该对象耦合严重,假如我们要更

换对象,所有 new 对象的地方都需要修

改一遍,这显然违背了软件设计的开闭

原则,如果我们使用工厂来生产对象,

我们就只和工厂打交道就可以了,彻底

和对象解耦,如果要更换对象,直接在

工厂里更换该对象即可,达到了与对象

解耦的目的;所以说,工厂模式最大的

优点就是:解耦

1. 简单工厂 (Simple Factory)

定义:

一个工厂方法,依据传入的参数,生成对

应的产品对象;

角色:

① 抽象产品
② 具体产品
③ 具体工厂
④ 产品使用者

使用说明:

先将产品类抽象出来,比如,苹果和梨都属

于水果,抽象出来一个水果类 Fruit,苹果和

梨就是具体的产品类,然后创建一个水果工

厂,分别用来创建苹果和梨

代码如下:

// 水果接口:
public interface Fruit {void whatIm();
}// 苹果类:
public class Apple implements Fruit {@Overridepublic void whatIm() {System.out.println("苹果");}
}// 梨类:
public class Pear implements Fruit {@Overridepublic void whatIm() {System.out.println("梨");}
}//水果工厂:public class FruitFactory {public Fruit createFruit(String type) {if (type.equals("apple")) {//生产苹果return new Apple();} else if (type.equals("pear")) {//生产梨return new Pear();}return null;}
}// 使用工厂生产产品:
public class FruitApp {public static void main(String[] args) {FruitFactory mFactory = new FruitFactory();Apple apple = (Apple) mFactory.createFruit("apple");//获得苹果Pear pear = (Pear) mFactory.createFruit("pear");//获得梨apple.whatIm();pear.whatIm();}
}

以上的这种方式,每当添加一种水果,就必

然要修改工厂类,违反了开闭原则;

所以简单工厂只适合于产品对象较少,且产

品固定的需求,对于产品变化无常的需求来

说显然不合适

2. 工厂方法 (Factory Method)

定义:

将工厂提取成一个接口或抽象类,具体生

产什么产品由子类决定

角色:

① 抽象产品
② 具体产品
③ 抽象工厂
④ 具体工厂

使用说明:

和上例中一样,产品类抽象出来,这次我们

把工厂类也抽象出来,生产什么样的产品由

子类来决定

代码如下:

// 水果接口、苹果类和梨类:代码和上例一样// 抽象工厂接口:
public interface FruitFactory {Fruit createFruit();//生产水果
}// 苹果工厂:
public class AppleFactory implements FruitFactory {@Overridepublic Apple createFruit() {return new Apple();}
}// 梨工厂:
public class PearFactory implements FruitFactory {@Overridepublic Pear createFruit() {return new Pear();}
}// 使用工厂生产产品:
public class FruitApp {public static void main(String[] args){AppleFactory appleFactory = new AppleFactory();PearFactory pearFactory = new PearFactory();Apple apple = appleFactory.createFruit();//获得苹果Pear pear = pearFactory.createFruit();//获得梨apple.whatIm();pear.whatIm();}
}

以上这种方式,虽然解耦了,也遵循了开闭

原则,但是如果我需要的产品很多的话,需

要创建非常多的工厂,所以这种方式的缺点

也很明显

3. 抽象工厂 (Abstract Factory)

定义:

为创建一组相关或者是相互依赖的对象提供

的一个接口,而不需要指定它们的具体类

角色:

① 抽象产品
② 具体产品

③ 抽象工厂

④ 具体工厂

使用说明:

抽象工厂和工厂方法的模式基本一样,区别

在于,工厂方法是生产一个具体的产品,而

抽象工厂可以用来生产一组相同,有相对关

系的产品

用抽象工厂来实现:

// cpu接口和实现类:
public interface Cpu {void run();class Cpu650 implements Cpu {@Overridepublic void run() {System.out.println("650 也厉害");}}class Cpu825 implements Cpu {@Overridepublic void run() {System.out.println("825 更强劲");}}
}// 屏幕接口和实现类:
public interface Screen {void size();class Screen5 implements Screen {@Overridepublic void size() {System.out.println("" + "5寸");}}class Screen6 implements Screen {@Overridepublic void size() {System.out.println("6寸");}}
}// 抽象工厂接口:
public interface PhoneFactory {Cpu getCpu();//使用的cpuScreen getScreen();//使用的屏幕
}// 小米手机工厂:
public class XiaoMiFactory implements PhoneFactory {@Overridepublic Cpu.Cpu825 getCpu() {return new Cpu.Cpu825();//高性能处理器}@Overridepublic Screen.Screen6 getScreen() {return new Screen.Screen6();//6寸大屏}
}//红米手机工厂:
public class HongMiFactory implements PhoneFactory {@Overridepublic Cpu.Cpu650 getCpu() {return new Cpu.Cpu650();//高效处理器}@Overridepublic Screen.Screen5 getScreen() {return new Screen.Screen5();//小屏手机}
}// 使用工厂生产产品:
public class PhoneApp {public static void main(String[] args){HongMiFactory hongMiFactory = new HongMiFactory();XiaoMiFactory xiaoMiFactory = new XiaoMiFactory();Cpu.Cpu650 cpu650 = hongMiFactory.getCpu();Cpu.Cpu825 cpu825 = xiaoMiFactory.getCpu();cpu650.run();cpu825.run();Screen.Screen5 screen5 = hongMiFactory.getScreen();Screen.Screen6 screen6 = xiaoMiFactory.getScreen();screen5.size();screen6.size();}
}

以上例子可以看出,抽象工厂可以解决一

系列的产品生产的需求,对于大批量,多

系列的产品,用抽象工厂可以更好地管理

和扩展

4. 三种工厂方式总结

① 对于简单工厂和工厂方法来说,两者的

    使用方式实际上是一样的,如果对于产

    品的分类和名称是确定的,数量是相对

    固定的,推荐使用简单工厂模式;

② 抽象工厂用来解决相对复杂的问题,适用于

    一系列、大批量的对象生产

相关文章:

Java面试题--设计模式

一、Java 中有几种设计模式? Java 中一般认为有 23 种设计模式 分为三大类: 1. 创建型模式 5 种 ① 工厂方法模式 ② 抽象工厂模式 ③ 单例模式 ④ 建造者模式 ⑤ 原型模式 2. 结构型模式 7 种 ① 适配器模式 ② 装饰器模式 ③ 代理模式 ④ 外观模式 …...

【VS Code插件开发】Webview面板(三)

🐱 个人主页:不叫猫先生,公众号:前端舵手 🙋‍♂️ 作者简介:前端领域优质作者、阿里云专家博主,共同学习共同进步,一起加油呀! 📢 资料领取:前端…...

WebDriver API及对象识别技术

html页面的iframe的切换 定位到客户管理 新增客户 会无法定位到新增客户,因为在另外一个iframe框架之中。 iframe是html中的框架标签,表示文档中可以嵌入文档,或者说是浮动的框架。在selenium中iframe同样如此,如果驱动器对…...

计算机视觉之三维重建(一)(摄像机几何)

针孔摄像机 添加屏障: 使用针孔(o光圈针孔摄像机中心),实现现实与成像一对一映射,减少模糊。其中针孔与像平面的距离为f(焦距);虚拟像平面位于针孔与真实物体之间,与像平面互为倒立关系。位置映射:利用相似…...

机器学习算法-随机森林

目录 机器学习算法-随机森林 (1)构建单棵决策树。 决策树的构建过程 决策树的构建一般包含三个部分:特征选择、树的生成、剪枝。 机器学习算法-随机森林 机器学习算法-随机森林 随机森林是一种监督式学习算法,适用于分类和回…...

Springboot 实践(10)spring cloud 与consul配置运用之服务的注册与发现

前文讲解,完成了springboot、spring security、Oauth2.0的继承,实现了对系统资源的安全授权、允许获得授权的用户访问,也就是实现了单一系统的全部技术开发内容。 Springboot是微服务框架,单一系统只能完成指定系统的功能&#xf…...

解决方案:如何在 Amazon EMR Serverless 上执行纯 SQL 文件?

《大数据平台架构与原型实现:数据中台建设实战》一书由博主历时三年精心创作,现已通过知名IT图书品牌电子工业出版社博文视点出版发行,点击《重磅推荐:建大数据平台太难了!给我发个工程原型吧!》了解图书详…...

pytorch lightning和pytorch版本对应

参见官方文档: https://lightning.ai/docs/pytorch/latest/versioning.html#compatibility-matrix 下图左一列(lightning.pytorch)安装命令:pip install lightning --use-feature2020-resolver 下图左一列(pytorch_lig…...

Postman返回了一个html页面

问题记录 调用公司的测试环境接口,从浏览器控制台接口处cCopy as cURL(cmd),获取完整的请求内容,然后导入postman发起请求 提测时发现返回一个html页面,明显是被请求在网管处被拦截了,网关返回的这个报错html页面 …...

centos服务器搭建宝塔面板

因为电脑无线网无法登录宝塔,也无法ssh到服务器,但是热点可以连接,网上没找到解决方法,重装下。 解决办法,先追路由,结果是被防火墙拦截了,解封以后还不行,重新查,联动的…...

【微信小程序】记一次自定义微信小程序组件的思路

最近来个需求,要求给小程序的 modal 增加个关闭按钮,上网一查发现原来 2018 年就有人给出解决方案了,于是总结下微信小程序自定义组件的思路:一句话,用 wxml css实现和原生组件类似的样式和效果,之后用 JS…...

TiDB数据库从入门到精通系列之四:SQL 基本操作

TiDB数据库从入门到精通系列之四:SQL 基本操作 一、SQL 语言分类二、查看、创建和删除数据库三、创建、查看和删除表四、创建、查看和删除索引五、记录的增删改六、查询数据七、创建、授权和删除用户 成功部署 TiDB 集群之后,便可以在 TiDB 中执行 SQL 语…...

Azure创建自定义VM镜像

创建一个虚拟机,参考 https://blog.csdn.net/m0_48468018/article/details/132267096,入站端口开启80,22 进行远程远程连接 使用CLI命令部署NGINX,输入如下命令 sudo su apt-get update -y apt-get install nginx git -y最后的效果 4. 关闭…...

react 10之状态管理工具2 redux + react-redux +redux-saga

目录 react 10之状态管理工具2 redux store / index.js 入口文件actionType.js actions常量的文件rootReducer.js 总的reducer 用于聚合所有模块的 reducerrootSaga.js 总的saga 用于聚合所有模块的 sagastore / form / formActions.js 同步修改 isShowstore / form / formRedu…...

gor工具http流量复制、流量回放,生产运维生气

gor是一款流量复制回放工具,gor工具的官网:https://goreplay.org/ 1、对某个端口的http流量进行打印 ./gor --input-raw :8000 --output-stdout 2、对流量实时转发,把81端口流量转发到192.168.3.221:80端口 ./gor --input-raw :81--output-ht…...

设计模式之单例设计模式

单例设计模式 2.1 孤独的太阳盘古开天,造日月星辰。2.2 饿汉造日2.3 懒汉的队伍2.4 大道至简 读《秒懂设计模式总结》 单例模式(Singleton)是一种非常简单且容易理解的设计模式。顾名思义,单例即单一的实例,确切地讲就是指在某个系统中只存在…...

Java自学到什么程度就可以去找工作了?

引言 Java作为一门广泛应用于软件开发领域的编程语言,对于初学者来说,了解到什么程度才能开始寻找实习和入职机会是一个常见的问题。 本文将从实习和入职这两个方面,分点详细介绍Java学习到什么程度才能够开始进入职场。并在文章末尾给大家安…...

三、Kafka生产者

目录 3.1 生产者消息发送流程3.1.1 发送原理 3.2 异步发送 API3.3 同步发送数据3.4 生产者分区3.4.1 kafka分区的好处3.4.2 生产者发送消息的分区策略3.4.3 自定义分区器 3.5 生产者如何提高吞吐量3.6 数据可靠性 3.1 生产者消息发送流程 3.1.1 发送原理 3.2 异步发送 API 3…...

【SA8295P 源码分析】19 - QNX Host NFS 文件系统配置

【SA8295P 源码分析】19 - QNX Host NFS 文件系统配置 一、NFS Server二、NFS Client三、NFS 相关的文件及目录四、将文件放入QNX 文件系统中五、编译下载验证系列文章汇总见:《【SA8295P 源码分析】00 - 系列文章链接汇总》 本文链接:《【SA8295P 源码分析】19 - QNX Host N…...

JRE、JDK、JVM及JIT之间有什么不同?_java基础知识总结

当涉及Java编程和执行时,以下术语具有不同的含义: 1.JRE (Java Runtime Environment) JRE是Java运行时环境的缩写。它是一个包含用于在计算机上运行Java应用程序所需的组件集合。JRE包括了以下几个主要部分: Java虚拟机(JVM):用…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 ​…...

Python Einops库:深度学习中的张量操作革命

Einops(爱因斯坦操作库)就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库,用类似自然语言的表达式替代了晦涩的API调用,彻底改变了深度学习工程…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist

现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...