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是微服务框架,单一系统只能完成指定系统的功能…...
解决方案:如何在 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):用…...
sqlite3数据库的实现
sqlite3代码实现数据库的插入、删除、修改、退出功能 #include <head.h> #include <sqlite3.h> #include <unistd.h> int do_insert(sqlite3 *db); int do_delete(sqlite3 *db); int do_update(sqlite3 *db);int main(int argc, const char *argv[]) {sqlit…...
c#设计模式-结构型模式 之 桥接模式
前言 桥接模式是一种设计模式,它将抽象与实现分离,使它们可以独立变化。这种模式涉及到一个接口作为桥梁,使实体类的功能独立于接口实现类。这两种类型的类可以结构化改变而互不影响。 桥接模式的主要目的是通过将实现和抽象分离,…...
【Vue-Router】导航守卫
前置守卫 main.ts import { createApp } from vue import App from ./App.vue import {router} from ./router // import 引入 import ElementPlus from element-plus import element-plus/dist/index.css const app createApp(App) app.use(router) // use 注入 ElementPlu…...
07无监督学习——降维
1.降维的概述 维数灾难(Curse of Dimensionality):通常是指在涉及到向量的计算的问题中,随着维数的增加,计算量呈指数倍增长的一种现象。 1.1什么是降维? 1.降维(Dimensionality Reduction)是将训练数据中的样本(实例)从高维空间转换到低维…...
系列七、IOC操作bean管理(xml自动装配)
一、概述 自动装配是根据指定规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入。 二、分类 xml自动装配分为按照属性名称自动装配(byName)和按照属性类型自动装配(byType)。 2.1…...
01- vdom 和模板编译源码
组件渲染的过程 template --> ast --> render --> vDom --> 真实的Dom --> 页面 Runtime-Compiler和Runtime-Only的区别 - 简书 编译步骤 模板编译是Vue中比较核心的一部分。关于 Vue 编译原理这块的整体逻辑主要分三个部分,也可以说是分三步&am…...
C++入门知识点——解决C语言不足
😶🌫️Take your time ! 😶🌫️ 💥个人主页:🔥🔥🔥大魔王🔥🔥🔥 💥代码仓库:🔥🔥魔…...
探秘分布式大数据:融合专业洞见,燃起趣味火花,启迪玄幻思维
文章目录 一 数据导论二 大数据的诞生三 大数据概论3.1 大数据的5V特征3.2 大数据的工作核心 四 大数据软件生态4.1 数据存储软件4.2 数据计算软件4.3 数据传输软件 五 Apache Hadoop概述5.1 Apache Hadoop框架5.2 Hadoop的功能5.3 Hadoop的发展5.4 Hadoop发行版本 一 数据导论…...
什么是 SPI,和API有什么区别?
面试回答 Java 中区分 API 和 SPI,通俗的讲:API 和 SPI 都是相对的概念,他们的差别只在语义上,API 直接被应用开发人员使用,SPI 被框架扩展人员使用。 API Application Programming Interface 大多数情况下ÿ…...
python3 安装clickhouse_sqlalchemy(greenlet) 失败
环境信息: centos7操作系统,python3.8 执行pip3 install clickhouse_sqlalchemy或者pip3 install greenlet报以下报错: Command "/opt/python3.6.10-customized/bin/python3.6 -u -c "import setuptools, tokenize;file/tmp/pip-in…...
超炫的网站/网络推广策划方案怎么写
1:java 的最大特点及实现原理跨平台实现原理:java首先利用文本编辑器编写java源程序,源文件的后缀名为.java;再利用编译器(javac)将程序编译为字节码文件,字节码文件的后缀名.class;…...
珠海做网站优化的公司/万网阿里云域名查询
怪自己大学C语言学的不扎实,下面的程序看了好久才破解,大神见谅,写下总结吧 程序先贴出来: 定义如下:子程序如下:实际调用如下刚开始看的时候,死活没搞懂,后来通过验证什么的弄懂了&…...
那个网站是响应式的/企业营销策划
博主说:在本篇文章中,马化腾先生亲口讲述了自己的创业史,回顾了早期创业之艰辛、公司生存之法则,从“创业维艰、自我颠覆、产品思维和最大担忧”四个方面分别进行了阐述,值得每一个互联网人为之深思。 正文 创业维艰 我…...
做网站的价格/怎么快速优化关键词排名
在双十一购买完智能电视后,安装自己喜欢的软件,或许是在正常不过的事情了,但有时候我们会碰到一些APK无法识别,这个时候还以为会认为自己买的是假货,但实际上,这并不是电视的问题,而今天小编就教大家,一旦碰倒APK无法识别时应该如何解决,帮助你能拥有更好的观看体验。首先就是要…...
建设网站方法/搜索引擎优化的主要工作有
题意: 给出科学计数法的形式,转化成常规的表示,要求保留所有的有效位数 思路:纯粹的字符串处理问题,注意边界条件即可。如1.23E02这种,转化后是123,既不需要补0,也不需要添加小数点。…...
佛山百度快照优化排名/株洲seo优化
0,Matlab语言的介绍 1.什么叫计算? 在汉语中,“计算”一词的含义: 谋划 ,考虑 , 算计。随着电子计算机的产生与应用,人们对“计算”的理解发生了很大的变化。 ÿ…...