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

设计模式(含7大原则)面试题

目录

主要参考文章

设计模式的目的

设计模式的七大原则

设计模式的三大分类及关键点

1、创建型模式(用于解耦对象的实例化过程)

2、结构型模式

3、行为型模式

23种设计模式(乱序--现学现写,不全面--应付面试为主)

单例模式

模板模式

哈哈哈哈哈


声明

此文只针对我个人的目前的理解程度来记录的,有的我知道的或者觉得没有必要写的内容我就会省略掉。并且主要针对面试,介绍的可能不是很全面,甚至有的地方不是很正确,请包涵。

主要参考文章

设计模式23模式介绍-CSDN博客

12-模板方法模式_12(模板方法模式)-CSDN博客

设计模式的目的

  • 可重用性 (即:相同功能的代码,不用多次编写)
  • 可扩展性 (即:当需要增加新的功能时,非常的方便,称为可维护)
  • 可靠性 (即:当我们增加新的功能后,对原来的功能没有影响)
  • 可读性 (即:编程规范性, 便于其他程序员的阅读和理解)
  • 使程序呈现高内聚,低耦合的特性。

设计模式的七大原则

固定记忆:单 开 里 依 接 合 迪。

设计模式的三大分类及关键点

1、创建型模式(用于解耦对象的实例化过程

单例模式某个类只能有一个实例,提供一个全局的访问点
工厂模式一个工厂类根据传入的参量决定创建出哪一种产品类的实例
抽象工厂模式创建相关或依赖对象的家族,而无需明确指定具体类
建造者模式封装一个复杂对象的创建过程,并可以按步骤构造
原型模式通过复制现有的实例来创建新的实例

2、结构型模式

装饰器模式动态的给对象添加新的功能
代理模式不修改原始对象,通过代理对象来间接访问原始对象,并在访问前后执行额外的操作
桥接模式将抽象部分和它的实现部分分离,使它们都可以独立的变化
适配器模式将一个类的方法接口转换成客户希望的另一个接口
组合模式将对象组合成树形结构以表示“部分-整体”的层次结构
外观模式对外提供一个统一的方法,来访问子系统中的一群接口
享元模式通过共享技术来有效的支持大量细粒度的对象

3、行为型模式

策略模式定义一系列算法,把他们封装起来,并且使它们可以相互替换
模板模式抽象父类定义一个算法,子类在不改变该算法结构的情况下重定义该算法的某些步骤
命令模式将命令请求封装为一个对象,使得可以用不同的请求来进行参数化
迭代器模式一种遍历访问聚合对象中各个元素的方法,不暴露该对象的内部结构
观察者模式对象间的一对多的依赖关系
仲裁者模式用一个中介对象来封装一系列的对象交互
备忘录模式在不破坏封装的前提下,保持对象的内部状态
解释器模式给定一个语言,定义它的文法的一种表示,并定义一个解释器
建造者模式允许一个对象在其对象内部状态改变时改变它的行为
责任链模式将请求的发送者和接收者解耦,使的多个对象都有处理这个请求的机会
访问者模式不改变数据结构的前提下,增加作用于一组对象元素的新功能


23种设计模式(乱序--现学现写,不全面--应付面试为主)

单例模式--创建型

某个类只能有一个实例,提供一个全局的访问点

单例模式要素:

  • 私有构造方法;
  • 私有静态引用指向自己实例 ;
  • 以自己实例为返回值的公有静态方法;

单例模式好处:

  • 单例模式只允许创建一个对象,因此节省内存;
  • 避免了频繁的对象创建,可以加快对象访问速度。

单例模式场景:

  • 需要频繁实例化然后销毁的对象;
  • 创建对象时耗时过多或者耗资源过多,但又经常用到的对象;
  • 有状态的工具类对象;

单例模式的实现方式分类:

饿汉式单例:

//线程安全的
public class Singleton {//单例模式,构造器要私有化。private Singleton() {}//私有的静态的常量--私有静态引用指向自己实例。//【因为是static修饰的属性,所以是在类加载的时候就被创建,//后期不会再改变,所以线程是安全的!】private static final Singleton single = new Singleton();//以自己实例为返回值的公有静态方法。public static Singleton getInstance() {return single;}
}

懒汉式单例:

//有线程安全的问题,不推荐使用
//就算是使用了[加锁+双重判断]的解救办法,性能还是被损耗了。
public class SingletonTest {public static SingletonTest singleton = null;public static SingletonTest getInstance(){if(singleton == null){singleton = new SingletonTest();}return singleton;}//单例模式,构造器要私有化private SingletonTest {}
}

DCL(Double Check双重判断 + Lock加锁)懒汉式单例但线程安全,推荐使用:

//线程安全的
public class Singleton {private volatile static Singleton singleton;public static Singleton getSingleton(){//双重判断之一if(singleton==null){//加锁synchronized (Singleton.class) {//双重判断之二if (singleton == null) {singleton = new Singleton();}}}return singleton;}//构造函数私有化private Singleton(){}
}

静态内部类(懒汉式单例但线程安全):

//线程安全的
//外部类加载时并不需要立即加载内部类,内部类不被加载则不去初始化INSTANCE,故而不占内存。
//第一次调用getInstance()方法会导致虚拟机加载SingleTonHoler类且初始化INSTANCE。
//在创建时是否有并发问题? => 没有没有,类加载时jvm会保证线程安全性!
public class Singleton {//静态内部类private static class SingleTonHoler{private static Singleton INSTANCE = new Singleton();}public static Singleton getInstance(){return SingleTonHoler.INSTANCE;}//单例模式,构造器要私有化private Singleton {}
}

枚举类(饿汉式):

//枚举单例属于懒汉式还是饿汉式:饿汉式,内部枚举类相当于静态成员变量,
//类加载时就会创建,因此也是线程安全的。
public class SingletonObject7 {private SingletonObject7(){}/*** 枚举类型是线程安全的,并且只会装载一次*/private enum Singleton{INSTANCE;private final SingletonObject7 instance;Singleton(){instance = new SingletonObject7();}private SingletonObject7 getInstance(){return instance;}}public static SingletonObject7 getInstance(){//内部枚举类相当于静态成员变量return Singleton.INSTANCE.getInstance();}
}

破坏单例模式的场景及解决办法:

1、反射是通过调用构造方法生成新对象的,除枚举方式外,其他方式都会被反射破坏单例,所以如果我们想要阻止单例破坏,可以在构造方法中进行判断,若已有实例,则阻止生成新的实例,解决办法如下。

private SingletonObject(){if (instance != null) {throw new RuntimeException("实例已经存在,请通过 getInstance()方法获取");}
}

2、如果单例类实现了序列化接口Serializable, 就可以通过反序列化破坏单例(反序列化不会调用构造函数--反序列化会用到反射但不是通过反射调用构造函数而是ObjectInputStream类的私有的readObject()方法--使用ObjectInputStream.readObject()读取进来之后,如果是多次读取,就会创建多个实例),所以我们可以不实现序列化接口,如果非得实现序列化接口,可以在单例类中定义反序列化方法readResolve(),在反序列化时直接返回单例对象。

import java.io.Serializable;// Singleton Box:
class Box implements Serializable {private static Box instance = new Box("TEST");public static Box getInstance() {return Box.instance;}private Box(String name) {this.name = name;}private String name;@Overridepublic String toString() {return "Box " + name;}//【readResolve()方法】,如果不写此方法反序列化时会破坏单例private Object readResolve() {return Box.getInstance();}
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;public class Foo {public static void main(String[] args) {Box box = Box.getInstance();System.out.println(box.toString());try {ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("e:/box.out"));o.writeObject(box);o.close();} catch(Exception e) {e.printStackTrace();}Box box1 = null, box2 = null;try {ObjectInputStream in =new ObjectInputStream(new FileInputStream("e:/box.out"));box1 = (Box)in.readObject();in.close();} catch(Exception e) {e.printStackTrace();}try {ObjectInputStream in =new ObjectInputStream(new FileInputStream("e:/box.out"));box2 = (Box)in.readObject();in.close();} catch(Exception e) {e.printStackTrace();}System.out.println("box1.equals(box2) : " + box1.equals(box2));System.out.println(box1);System.out.println(box2);}
}

模板模式--行为型

抽象父类定义一个算法,子类在不改变该算法结构的情况下重定义该算法的某些步骤

算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中,提高了代码复用性。

自定义lamabda表达式也符合此设计模式。

案例:炒菜的步骤是固定的,分为倒油、热油、倒蔬菜、倒调料品、翻炒等步骤。

模板方法模式

/*** @ClassName: AbstractClass* @Description: 抽象类(定义模板方法和基本方法)* @Author: Sevenyear*/
public abstract class AbstractClass {//模板方法定义//【为防止恶意操作,模板方法一般都加上 final 关键词】public final void cookProcess() {pourOil();heatOil();pourVegetable();pourSauce();fry();}public void pourOil() {System.out.println("倒油");}//第二步:热油是一样的,所以直接实现public void heatOil() {System.out.println("热油");}//第三步:倒蔬菜是不一样的(一个下包菜,一个是下菜心)public abstract void pourVegetable();//第四步:倒调味料是不一样public abstract void pourSauce();//第五步:翻炒是一样的,所以直接实现public void fry(){System.out.println("炒啊炒啊炒到熟啊");}
}
/*** @ClassName: ConcreteClass_BaoCai* @Description: 炒包菜类* @Author: Sevenyear*/
public class ConcreteClass_BaoCai extends AbstractClass {@Overridepublic void pourVegetable() {System.out.println("下锅的蔬菜是包菜");}@Overridepublic void pourSauce() {System.out.println("下锅的酱料是辣椒");}
}
/*** @ClassName: ConcreteClass_BaoCai* @Description: 炒菜心类* @Author: Sevenyear*/
public class ConcreteClass_CaiXin extends AbstractClass {@Overridepublic void pourVegetable() {System.out.println("下锅的蔬菜是菜心");}@Overridepublic void pourSauce() {System.out.println("下锅的酱料是蒜蓉");}
}
public class Client {public static void main(String[] args) {//炒包菜//创建对象ConcreteClass_BaoCai baoCai = new ConcreteClass_BaoCai();//调用炒菜的功能baoCai.cookProcess();}
}

jdk案例:InputStream抽象父类中已经定义好了读取字节数组数据的方法是每次读取一个字节,并将其存储到数组的第一个空闲索引位置,循环读取len个字节数据。具体如何读取一个字节数据?是由子类实现的

public abstract class InputStream implements Closeable {//抽象方法,要求子类必须重写public abstract int read() throws IOException;public int read(byte b[]) throws IOException {return read(b, 0, b.length);}public int read(byte b[], int off, int len) throws IOException {if (b == null) {throw new NullPointerException();} else if (off < 0 || len < 0 || len > b.length - off) {throw new IndexOutOfBoundsException();} else if (len == 0) {return 0;}int c = read(); //调用了无参的read方法,该方法是每次读取一个字节数据if (c == -1) {return -1;}b[off] = (byte)c;int i = 1;try {for (; i < len ; i++) {c = read();if (c == -1) {break;}b[off + i] = (byte)c;}} catch (IOException ee) {}return i;}
}

在InputStream类中定义了多个 read() 方法,从上面代码可以看到,无参的 read() 方法是抽象方法,要求子类必须实现。而 read(byte b[]) 方法调用了 read(byte b[], int off, int len) 方法,所以在此处重点看的方法是带三个参数的方法。 在该方法中可以看到调用了无参的抽象的 read() 方法。


享元模式--结构型

java常量池(字符串常量池、Integer常量池)的实现其实是基于享元模式(通过共享技术来有效的支持大量细粒度的对象)的思想,可以节省创建的时间,并且节省空间。

字符串常量池在java1.8中是在Java堆中的。在编译期就存在的字符串将会直接存入这个池中,在不同代码地方的字面量形式的相同的字符串将会直接引用同一个字符串,为什么能这样引用是因为字符串的不可变性。


策略模式--行为型

comparable和comparator

相关文章:

设计模式(含7大原则)面试题

目录 主要参考文章 设计模式的目的 设计模式的七大原则 设计模式的三大分类及关键点 1、创建型模式&#xff08;用于解耦对象的实例化过程&#xff09; 2、结构型模式 3、行为型模式 23种设计模式&#xff08;乱序--现学现写&#xff0c;不全面--应付面试为主&#xff…...

claude3科普

Claude 3 是一系列由 Anthropic 推出的新一代 语言模型&#xff08;LLMs&#xff09;。Anthropic 是一家人工智能初创公司&#xff0c;其背后的投资者包括亚马逊等&#xff0c;总投资额达到 40亿美元12。 这一系列模型分为三个不同级别的能力&#xff0c;分别是&#xff1a; …...

2024中国·北京预制菜产业博览会

2024中国北京预制菜产业博览会 时间&#xff1a;2024年5月25-27日 地点&#xff1a;北京中国国际展览中心 主办单位&#xff1a;北京鸿利展览服务有限公司 承办单位&#xff1a;北京预制菜博览会组委会 北京鸿利展览服务有限公司 预制菜产业“一头连着餐桌&#xff0c;一头…...

【Vue】vue3 在图片上渲染 OCR 识别后的文本框、可复制文本组件

需求 后面返回解析后的文本和四角坐标&#xff0c;在图片上渲染成框&#xff0c;并且可复制。图片还可以缩放、拖拽 实现 这里要重点讲下关于OCR文本框的处理&#xff1a; 因为一些文字可能是斜着放的&#xff0c;所有我们要特殊处理&#xff0c;根据三角函数来计算出它的偏…...

Linux系统运维脚本:批量创建linux用户和密码(读取文件中的账号和密码来批量创建用户)

目 录 一、要求 二、解决方案 &#xff08;一&#xff09;解决思路 &#xff08;二&#xff09;方案 三、脚本程序实现 &#xff08;一&#xff09;脚本代码和解释 1、脚本代码 2、代码解释 &#xff08;二&#xff09;脚本验证 1、脚本编辑 2、给予执行权…...

重力坝廊道量水堰计与堰板安装技术指南

在水利工程中&#xff0c;重力坝廊道量水堰计的安装是确保水资源有效监测与管理的关键环节。本文将详细阐述量水堰计及量水堰板的安装方法&#xff0c;以确保安装质量&#xff0c;提高水资源利用效率。 一、量水堰计的安装位置 量水堰计应安装在堰板的上游&#xff0c;距离堰板…...

ButterKnife实现之Android注解处理器使用教程

ButterKnife实现之Android注解处理器使用教程 1、新建一个注解 1.1、编译时注解 创建注解所需的元注解Retention包含3个不同的值&#xff0c;RetentionPolicy.SOURCE、RetentionPolicy.CLASS、RetentionPolicy.RUNTIME。这3个值代表注解不同的保留策略。 使用RetentionPolic…...

【哈希】Leetcode 128. 最长连续序列 【中等】

最长连续序列 给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。请你设计并实现时间复杂度为 O(n) 的算法解决此问题。示例 1&#xff1a;输入&#xff1a;nums [100,4,200,1,3,2]输出&#x…...

回溯是怎么回事(算法村第十八关青铜挑战)

组合 77. 组合 - 力扣&#xff08;LeetCode&#xff09; 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [[2,4],[3,4],[2,3],[1,2],[1,3],…...

向爬虫而生---Redis 探究篇5<Redis集群刨根问底(1)>

前言: Redis集群是一种可靠和高性能的分布式数据库解决方案。随着互联网的迅速发展和数据规模的增长,传统的单机Redis已经无法满足大规模应用的需求。Redis集群的出现填补了这一空白,提供了更高的可扩展性和容错性。 大家都知道,Redis是一种基于内存的高性能键值存储数据库,…...

系统集成Prometheus+Grafana

根据产品需求在自己的系统中添加一个系统监控的页面&#xff0c;其中有主机信息的显示&#xff0c;也有一些业务信息的显示。调研后的方案是 主机信息通过Prometheus采集和存储&#xff0c;业务信息通过自己系统的调度任务统计后存储在Mysql中&#xff0c;使用Grafana对接Prome…...

实例驱动计算机网络

文章目录 计算机网络的层次结构应用层DNSHTTP协议HTTP请求响应过程 运输层TCP协议TCP协议面向连接实现TCP的三次握手连接TCP的四次挥手断开连接 TCP协议可靠性实现TCP的流量控制TCP的拥塞控制TCP的重传机制 UDP协议 网际层IP协议&#xff08;主机与主机&#xff09;IP地址的分类…...

Unity 报错:SSL CA certificate error

使用UnityWebRequest时出现如下报错&#xff1a; SSL CA certificate error Curl error 60: Cert verify failed: UNITYTLS_X509VERIFY_FLAG_USER_ERROR1 原因&#xff1a; 证书验证失败 和 SSL CA证书错误 解决方法&#xff1a; 创建一个如下的类&#xff1a; /// <…...

算法刷题Day1 | 704.二分查找、27.移除元素

目录 0 引言1 二分查找1.1 我的解题1.2 修改后1.3 总结 2 移除元素2.1 暴力求解2.2 双指针法&#xff08;快慢指针&#xff09; &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;算法专栏&#x1f4a5; 标题&#xff1a;代码随想录算法训练营第一天…...

大数据技术学习笔记(五)—— MapReduce(2)

目录 1 MapReduce 的数据流1.1 数据流走向1.2 InputFormat 数据输入1.2.1 FileInputFormat 切片源码、机制1.2.2 TextInputFormat 读数据源码、机制1.2.3 CombineTextInputFormat 切片机制 1.3 OutputFormat 数据输出1.3.1 OutputFormat 实现类1.3.2 自定义 OutputFormat 2 Map…...

北斗导航 | 同步双星故障的BDS/GPS接收机自主完好性监测算法

===================================================== github:https://github.com/MichaelBeechan CSDN:https://blog.csdn.net/u011344545 ===================================================== 同步双星故障的BDS/GPS接收机自主完好性监测算法 1 引言2 同步双星故障…...

2024金三银四必看前端面试题!简答版精品!

文章目录 导文面试题 导文 2024金三银四必看前端面试题&#xff01;2w字精品&#xff01;简答版 金三银四黄金期来了 想要跳槽的小伙伴快来看啊 面试题 基于您给出的方向&#xff0c;我将为您生成20个面试题和答案。请注意&#xff0c;由于面试题的答案可能因个人经验和理解而…...

Python-sklearn.datasets-make_blobs

​​​​​​sklearn.datasets.make_blobs()函数形参详解 """ Title: datasets for regression Time: 2024/3/5 Author: Michael Jie """from sklearn import datasets import matplotlib.pyplot as plt# 产生服从正态分布的聚类数据 x, y, cen…...

[最佳实践] conda环境内安装cuda 和 Mamba的安装

Mamba安装失败的过程中&#xff0c;causal-conv1d安装报错为连接超时 key word: vision mamba&#xff0c; DL &#xff0c;深度学习 &#xff0c;mamba unet&#xff0c;mamba环境安装 Mamba安装 主要故障是 pip install causal-conv1d1.2.0和 pip install mamba-ssm1.2.0 安…...

【算法】顺时针打印矩阵(图文详解,代码详细注释

目录 题目 代码如下: 题目 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。例如:如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则打印出数字:1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10 这一道题乍一看,没有包含任何复杂的数据结构和…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...