2023 设计模式中级面试题30道

x33g5p2x  于2023-01-26 发布在 其他  
字(8.2k)|赞(0)|评价(0)|浏览(1347)

1、 你当初为什么要学习设计模式?

  • 为了看懂源代码:如果不懂设计模式的话,去看Jdk、Spring、SpringMVC、IO等的源码,会感到很迷惑,什么都看不懂。
  • 为了看看前辈们的代码:比如去工作不一定是直接分配给我新项目,很有可能是前辈的项目,如果他们用了设计模式,而自己不会,那会面临很大问题。
  • 为了敲自己的理想中的优质代码:生活需要仪式感,需要认真生活,对于代码,也是一样,自己开发的项目就想把项目当成自己的大宝贝一样。

2、 知道责任链模式吗?

是行为型设计模式之一,其将链中每一个节点看作是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一节点对象。当一个请求从链式的首端发出时,会沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止。
优点
解耦了请求与处理;
请求处理者(节点对象)只需关注自己感兴趣的请求进行处理即可,对于不感兴趣的请求,直接转发给下一级节点对象;
具备链式传递处理请求功能,请求发送者无需知晓链路结构,只需等待请求处理结果;
链路结构灵活,可以通过改变链路结构动态地新增或删减责任;
易于扩展新的请求处理类(节点),符合 开闭原则;
缺点
责任链路过长时,可能对请求传递处理效率有影响;
如果节点对象存在循环引用时,会造成死循环,导致系统崩溃;

生活案列:我们在公司内部发起一个OA审批流程,项目经理审批、部门经理审批。老板审批、人力审批。这就是生活中的责任链模式,每个角色的责任是不同。

SpringMVC中的拦截器和Mybatis中的插件机制,都是拦截器经典实现。

3、 使用工厂模式最主要的好处是什么?在哪里使用?

工厂模式的最大好处是增加了创建对象时的封装层次。如果你使用工厂来创建对象,之后你可以使用更高级和更高性能的实现来替换原始的产品实现或类,这不需要在调用层做任何修改。

4、 什么是设计模式?

设计模式(Design Pattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。

5、 建造者模式和工厂模式的区别

  1. 建造者模式创建的是同一个类不同表示的对象;工厂模式创建的是不同的类的不同的对象。
  2. 抽象工厂模式可以创建一系列同一个产品族的产品(如:电脑的各种配件),建造者模式可以把一系列同一个产品族的产品组装成更复杂的产品(电脑)。

6、  策略模式是什么?

策略(Strategy)模式的定义:该模式定义了一系列算法,并将每个算法封装起来,使它们 可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通 过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些 算法进行管理。 策略模式的主要优点如下 多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句。 策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转 移到父类里面,从而避免重复的代码。 策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同 的。 策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算 法。 策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的 分离。 其主要缺点如下 客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。 策略模式造成很多的策略类

7、 23 种设计模式的具体的每种模式的功能?

单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。

原型(Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例。

工厂方法(Factory Method)模式:定义一个用于创建产品的接口,由子类决定生产什么产品。

抽象工厂(AbstractFactory)模式:提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。

建造者(Builder)模式:将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。

代理(Proxy)模式:为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。

适配器(Adapter)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。

桥接(Bridge)模式:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。装饰(Decorator)模式:动态的给对象增加一些职责,即增加其额外的功能。

外观(Facade)模式:为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。 享元(Flyweight)模式:运用共享技术来有效地支持大量细粒度对象的复用。

组合(Composite)模式:将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性。

模板方法(TemplateMethod)模式:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。

策略(Strategy)模式:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。 命令(Command)模式:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。

职责链(Chain of Responsibility)模式:把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合。

状态(State)模式:允许一个对象在其内部状态发生改变时改变其行为能力。

观察者(Observer)模式:多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为。

中介者(Mediator)模式:定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。

迭代器(Iterator)模式:提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。

访问者(Visitor)模式:在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问。

备忘录(Memento)模式:在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它。

解释器(Interpreter)模式:提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。

8、 哪些地方用到了单例模式?

  • 应用程序的日志应用,一般是单例模式实现。
  • 多线程的线程池的设计,一般也是采用单例模式,因为线程池要方便对池中的线程进行控制
  • Windows的(任务管理器或者回收站),是单例模式,他不能打开俩个
  • 在项目种加载配置文件的类,一般是单例。
  • 一个项目的数据库连接池,一般是单例模式。因为数据库连接是一种数据库资源,每次都new的话,很消耗资源。
  • 在Spring中,每个bean默认就是单例的,这样做的优点是spring容器可以管理。
  • springmvc中,控制器对象是单例。
  • 在servlet中,每个servlet是单例。
  • 计数器使用的也是单例,然后保证同步访问。

9、 单例模式的特点是什么?

单例模式属于创建型模式,一个单例类在任何情况下都只存储一个实例,构造方法必须是私有的、由自己创建一个静态变量存储实例,对外提供一个静态共有方法获取实例。

优点是内存中只有一个实例,减少了开销,尤其是频繁创建和销毁实例的情况下并且可以避免对资源的多重占用。缺点是没有抽象类层,难以扩展,与单一职责原则冲突。

spring的ApplicationContext创建的bean实例都是单例对象,还有ServletContext。数据库连接池等都是单例模式。

10、 什么是单例?(或单例模式的核心作用是什么?)

保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。

11、 模板方法模式

模板方法模式是指定义一个算法骨架,将具体内容延迟到子类去实现。
优点:
提高代码复用性:将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中;
实现了反向控制:通过一个父类调用其子类的操作,通过对子类的具体实现扩展不同的行为,实现了反向控制并且符合开闭原则。

喝茶茶:烧水----放入茶叶—喝茶。放入的茶叶每个人自己的喜好不一样,有的是普洱、有的是铁观音等。

每日工作:上班打卡----工作—下班打卡。每个人工作的内容不一样,后端开发的、前端开发、测试、产品每个人的工作内容不一样。

12、 单例模式有哪些实现?

饿汉式:在类加载时就初始化创建单例对象,线程安全,但不管是否使用都创建对象可能会浪费内存。

懒汉式:在外部调用时才会加载,线程不安全,可以加锁保证线程安全但效率低。

双重检查锁:使用volatile以及多重检查来缩小锁的范围,提高效率。

静态内部类:同时解决饿汉式的内存浪费问题和懒汉式的线程安全问题。

枚举:不仅能避免线程安全问题,还能防止反序列化重新创建新的对象,绝对防止多次实例化,也能防止反射破解单例的问题。

13、 什么是里氏替换原则?

1、开闭原则(Open Close Principle)

开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

2、里氏代换原则(Liskov Substitution Principle)

里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科

3、依赖倒转原则(Dependence Inversion Principle)

这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。

4、接口隔离原则(Interface Segregation Principle)

这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。

5、迪米特法则(最少知道原则)(Demeter Principle)

为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

6、合成复用原则(Composite Reuse Principle)

原则是尽量使用合成/聚合的方式,而不是使用继承

14、 什么情况下会违反迪米特法则?为什么会有这个问题?

迪米特法则建议“只和朋友说话,不要陌生人说话”,以此来减少类之间的耦合。

15、 什么是设计模式?你是否在你的代码里面使用过任何设计模式?

设计模式是世界上各种各样程序员用来解决特定设计问题的尝试和测试的方法。设计模式是代码可用性的延伸

16、 简单工厂、工厂方法和抽象工厂有何区别?

工厂模式是分为三种,分别是简单工厂,工厂方法,抽象工厂。其中工厂方法和抽象工厂是GoF23种设计模式中的一种,而简单工厂则不是一种设计模式,更加可以理解的是一种编码时候约定俗成的一种习惯。那么,就在接下来三点中分别去分析理解工厂模式。

**简单工厂模式:**是由一个工厂对象创建产品实例,简单工厂模式的工厂类一般是使用静态方法,通过不同的参数的创建不同的对象实例,可以生产结构中的任意产品,不能增加新的产品;

  1. 简单工厂的优点:

  2. 不需要关心类的创建细节。

  3. 减轻类之间的耦合依赖,具体类的实现只是依赖于简单工厂,而不依赖其他类。

  4. 简单工厂的缺点:

  5. 扩展复杂,当简单工厂需要生产出另外一种产品的时候,需要扩展工厂的内部创建逻辑,比较有可能引起较大的故障

  6. 由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中

**工厂方法:**是定义一个创建对象的接口,让实现这个接口的的类去决定实例化具体的类。工厂方法让类的实例化推迟到实现接口的子类中进行。

**抽象工厂模式:**提供一个创建一系列相关或相互依赖对象的接口,而无需制定他们具体的类,生产多个系列产品;生产不同产品族的全部产品,不能新增产品,可以新增产品族;
区别:

  • 简单工厂:唯一工厂类,一个产品抽象类,工厂类的创建方法依据入参判断并创建具体产品对象。
  • 工厂方法:多个工厂类,一个产品抽象类,利用多态创建不同的产品对象,避免了大量的if-else判断。
  • 抽象工厂:多个工厂类,多个产品抽象类,产品子类分组,同一个工厂实现类创建同组中的不同产品,减少了工厂子类的数量。

17、  简单工厂和抽象工厂的区别?

简单工厂:用来生产同一等级结构中的任意产品,对于增加新的产品,无能为力。 工厂方法:用来生产同一等级结构中的固定产品,支持增加任意产品。

抽象工厂:用来生产不同产品族的全部产品,对于增加新的产品,无能为力;支持增加产品族。

18、 简单工厂模式、工厂方法模式、抽象工厂模式的区别?

简单工厂:根据传递给工厂类的不同参数创建不同的产品。例如:给生产汽车的工厂传递不同的参数生产不同的汽车。

工厂方法:根据自己的需要使用不同的工厂来生产产品。例如:我要一辆奥迪汽车,那么就找奥迪汽车的工厂来生产奥迪汽车。

抽象工厂:根据自己的需要使用不同的工厂来生产同一个产品族的多个产品。例如:我要一辆奥迪汽车,还要奥迪牌的手机(假如奥迪生产手机),那么就找奥迪的工厂来生产奥迪汽车和奥迪手机。

19、 知道享元模式吗?

顾名思义就是被共享的单元。享元模式的意图是复用对象,节省内存,前提是享元对象是不可变对象。
具体来讲,当一个系统中存在大量重复对象的时候,如果这些重复的对象是不可变对象,我们就可以利用享元模式将对象设计成享元,在内存中只保留一份实例,供多处代码引用。这样可以减少内存中对象的数量,起到节省内存的目的。
典型的使用场景:Integer中cache,就是享元模式很经典的实现。

20、 举一个用 Java 实现的装饰模式(decorator design pattern)?它是作用于对象层次还是类层次?

装饰模式增加强了单个对象的能力。Java IO 到处都使用了装饰模式,典型例子就是Buffered 系列类如 BufferedReader 和 BufferedWriter,它们增强了 Reader 和 Writer 对象,以实现提升性能的 Buffer 层次的读取和写入。

21、 在 Java 中,什么叫观察者设计模式(observer design pattern)?

观察者模式是基于对象的状态变化和观察者的通讯,以便他们作出相应的操作。简单的例子就是一个天气系统,当天气变化时必须在展示给公众的视图中进行反映。这个视图对象是一个主体,而不同的视图是观察者。

22、 享元模式和单例模式的区别?

单例模式是创建型模式,重在只能有一个对象。而享元模式是结构型模式,重在节约内存使用,提升程序性能。
享元模式:把一个或者多可对象霍村起来,用的时候,直接从缓存里获取。也就是说享元模式不一定只有一个对象。

23、 知道观察者模式吗?

观察者模式是定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
优点:
观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色;
观察者模式在观察目标和观察者之间建立一个抽象的耦合;
观察者模式支持广播通信;
观察者模式符合开闭原则(对拓展开放,对修改关闭)的要求。
缺点:
如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间;
如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃;
观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
在观察者模式中有如下角色:
Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象;
ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知;
Observer:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己;
ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。

在Spring中大量的使用的观察者模式,只要看到是以Event结尾或者Publish开头的基本上都是观察者模式。

24、 代理模式和装饰器模式有什么区别?

都是结构型模式,代理模式重在访问权限的控制,而装饰器模式重在功能的加强。

25、 ⼯⼚⽅法模式(利⽤创建同⼀接⼝的不同实例)

1、普通⼯⼚模式:建⽴⼀个⼯⼚类,对实现了同⼀接⼝的⼀些类进⾏实例的创建;

26、 抽象工厂模式了解吗?

抽象工厂模式指提供一个创建一系列相关或相互依赖对象的接口,无需指定它们的具体类。

客户端不依赖于产品类实例如何被创建和实现的细节,主要用于系统的产品有多于一个的产品族,而系统只消费其中一个产品族的情况。抽象工厂模式的缺点是不方便拓展产品族。,并且增加了系统的抽象性和理解难度。

java.sql.Connection接口就是一个抽象工厂,其中很多抽象产品如Statement,Blob,Savepoint

27、 抽象工厂模式

抽象工厂模式是在简单工厂的基础上将未来可能需要修改的代码抽象出来,通过继承的方式让子类去做决定。

比如,以上面的咖啡工厂为例,某天我的口味突然变了,不想喝咖啡了想喝啤酒,这个时候如果直接修改简单工厂里面的代码,这种做法不但不够优雅,也不符合软件设计的“开闭原则”,因为每次新增品类都要修改原来的代码。这个时候就可以使用抽象工厂类了,抽象工厂里只声明方法,具体的实现交给子类(子工厂)去实现,这个时候再有新增品类的需求,只需要新创建代码即可。

28、 Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式

单例模式重点在于在整个系统上共享一些创建时较耗资源的对象。整个应用中只维护一个特定类实例,它被所有组件共同使用。Java.lang.Runtime 是单例模式的经典例子。从 Java5 开始你可以使用枚举(enum)来实现线程安全的单例。

29、 了解过适配器模式么?

适配器模式是将一个类的接口变成客户端所期望的另一种接口,从而使原本因接口不匹配而无法一起工作的两个类能够在一起工作。
优点:
可以让两个没有关联的类一起运行,起着中间转换的作用;
灵活性好,不会破坏原有的系统。
缺点:
过多地使用适配器,容易使代码结构混乱,如明明看到调用的是 A 接口,内部调用的却是 B接口的实现。

生活中的插座,为了适应各种插头,然后上面有两个孔的,三个空的,基本都能适应。还有万能充电器、USB接口等。这些都是生活中的适配器模式。

30、 什么是单例模式?

单例模式是一种常用的软件设计模式,在应用这个模式时,单例对象的类必须保证只有一个实例存在,整个系统只能使用一个对象实例。

优点:不会频繁地创建和销毁对象,浪费系统资源。

使用场景:IO 、数据库连接、Redis 连接等。

相关文章

微信公众号

最新文章

更多

目录