持续总结中!2024年面试必问 20 道设计模式面试题(四)

2024-06-19 00:28

本文主要是介绍持续总结中!2024年面试必问 20 道设计模式面试题(四),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上一篇地址:持续总结中!2024年面试必问 20 道设计模式面试题(三)-CSDN博客

七、观察者模式(Observer Pattern)是如何工作的?

观察者模式(Observer Pattern),又称为发布-订阅模式,是一种行为设计模式,它定义了对象间的一种一对多的依赖关系,使得当一个对象状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这种模式通常用于实现分布式事件处理系统。

观察者模式的主要组件:

  1. 主题(Subject)

    • 主题是观察者模式的核心,它维护了一组观察者对象的引用,并提供接口用于注册(attach)、移除(detach)和通知(notify)观察者。
  2. 观察者(Observer)

    • 观察者是一个接口,定义了观察者对象必须实现的更新接口,以便在主题状态改变时得到通知。
  3. 具体主题(ConcreteSubject)

    • 具体主题实现了主题接口,存储状态信息,并提供方法供观察者注册和移除自己。当状态发生改变时,它会自动通知所有注册的观察者。
  4. 具体观察者(ConcreteObserver)

    • 具体观察者实现了观察者接口,根据主题的当前状态更新自己的状态。通常包含一个指向具体主题的引用,但这个引用不是必需的,取决于具体的实现。
  5. 客户端(Client)

    • 客户端代码创建并配置了具体主题和具体观察者,将观察者注册到主题上,并触发事件以演示观察者模式的工作。

观察者模式的工作原理:

  1. 注册观察者:具体观察者对象通过调用具体主题的注册方法将自己注册为观察者。

  2. 状态变更:当具体主题的状态发生变化时,它会调用所有注册观察者的更新方法。

  3. 通知观察者:具体主题通过调用观察者的更新方法来通知它们状态已经改变,通常传递一些必要的信息,如变化的状态本身或一个事件对象。

  4. 更新状态:具体观察者接收到通知后,根据传递的信息更新自己的状态。

示例代码(Java):

// 观察者接口
interface Observer {void update(String message);
}// 主题接口
interface Subject {void registerObserver(Observer o);void removeObserver(Observer o);void notifyObservers();
}// 具体主题
class ConcreteSubject implements Subject {private List<Observer> observers = new ArrayList<>();private String state;public void registerObserver(Observer o) {observers.add(o);}public void removeObserver(Observer o) {observers.remove(o);}public void notifyObservers() {for (Observer observer : observers) {observer.update(state);}}public void setState(String state) {this.state = state;notifyObservers();}
}// 具体观察者
class ConcreteObserver implements Observer {private ConcreteSubject subject;public ConcreteObserver(ConcreteSubject subject) {this.subject = subject;subject.registerObserver(this);}@Overridepublic void update(String message) {System.out.println("Received update: " + message);}
}// 客户端代码
public class ObserverPatternDemo {public static void main(String[] args) {ConcreteSubject subject = new ConcreteSubject();new ConcreteObserver(subject); // 注册观察者subject.setState("State 1"); // 状态变更,通知观察者subject.setState("State 2"); // 再次状态变更}
}

在这个示例中,ConcreteSubject是具体主题,它维护了一个观察者列表,并在状态变化时通知所有观察者。ConcreteObserver是具体观察者,实现了Observer接口,并在接收到更新时打印消息。客户端代码创建了主题和观察者,并演示了状态更新和观察者注册的过程。

观察者模式使得对象间的耦合度降低,当一个对象的状态变化时,依赖于它的对象会自动更新,而无需直接调用这些对象的方法。这使得系统更加灵活和易于维护。

八、装饰器模式(Decorator Pattern)和适配器模式有何不同?

装饰器模式(Decorator Pattern)和适配器模式(Adapter Pattern)虽然都是结构型设计模式,但它们解决的问题和设计目的是不同的。以下是两种模式的主要区别:

目的不同:

  • 适配器模式 主要用于使不兼容的接口能够一起工作。它通常用于将一个类的接口转换成客户端期望的另一个接口,从而让原本由于接口不兼容而不能一起工作的类可以协同工作。

  • 装饰器模式 主要用于动态地给一个对象添加额外的职责。它允许用户在不修改原始对象的基础上,通过添加装饰类来扩展对象的功能。

结构不同:

  • 适配器模式 包含以下角色:

    • 目标接口(Target):希望适配的接口。
    • 适配者(Adaptee):需要适配的类。
    • 适配器(Adapter):通过在内部包装一个适配者对象,把源接口转换成目标接口。
  • 装饰者模式 包含以下角色:

    • 抽象组件(Component):定义了被装饰接口。
    • 具体组件(ConcreteComponent):实现了抽象组件的具体类。
    • 抽象装饰者(Decorator):抽象类,实现了装饰接口,并持有一个装饰接口的引用。
    • 具体装饰者(ConcreteDecorator):实现抽象装饰者,添加额外的职责。

使用场景不同:

  • 适配器模式 常用于以下场景:

    • 需要将一个已有的类集成到一个新系统中,但接口不兼容。
    • 需要复用一些已有的类,但这些类的接口与新系统的接口不一致。
  • 装饰者模式 常用于以下场景:

    • 需要动态地给对象添加职责,同时希望避免使用继承带来的耦合。
    • 需要通过一种灵活的方式来扩展对象的功能,同时保持对象的开放封闭原则。

行为不同:

  • 适配器模式 通常只关注于接口的转换,不涉及对象功能的扩展。

  • 装饰者模式 允许通过多个装饰者的嵌套使用,来逐步添加多个职责,形成一种链式结构。

示例:

  • 适配器模式示例:假设有一个第三方音乐播放器类ThirdPartyMusicPlayer,它有一个playMusic()方法。你的系统需要一个play()方法的接口。可以创建一个适配器MusicPlayerAdapter,它实现了play()方法,内部调用ThirdPartyMusicPlayerplayMusic()方法。

  • 装饰者模式示例:假设有一个Coffee类,有一个cost()方法返回咖啡的价格。为了添加如加糖、加牛奶等额外服务,可以创建一个装饰者CoffeeDecorator,它持有一个Coffee对象的引用,并在调用cost()方法时添加额外的费用。

总结来说,适配器模式主要用于接口转换,而装饰者模式主要用于对象功能的动态扩展。两者虽然都可以用于复用已有的代码,但它们关注的问题和实现方式是不同的。

这篇关于持续总结中!2024年面试必问 20 道设计模式面试题(四)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1073484

相关文章

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

Python实现图片分割的多种方法总结

《Python实现图片分割的多种方法总结》图片分割是图像处理中的一个重要任务,它的目标是将图像划分为多个区域或者对象,本文为大家整理了一些常用的分割方法,大家可以根据需求自行选择... 目录1. 基于传统图像处理的分割方法(1) 使用固定阈值分割图片(2) 自适应阈值分割(3) 使用图像边缘检测分割(4)

Windows Docker端口占用错误及解决方案总结

《WindowsDocker端口占用错误及解决方案总结》在Windows环境下使用Docker容器时,端口占用错误是开发和运维中常见且棘手的问题,本文将深入剖析该问题的成因,介绍如何通过查看端口分配... 目录引言Windows docker 端口占用错误及解决方案汇总端口冲突形成原因解析诊断当前端口情况解

数据库面试必备之MySQL中的乐观锁与悲观锁

《数据库面试必备之MySQL中的乐观锁与悲观锁》:本文主要介绍数据库面试必备之MySQL中乐观锁与悲观锁的相关资料,乐观锁适用于读多写少的场景,通过版本号检查避免冲突,而悲观锁适用于写多读少且对数... 目录一、引言二、乐观锁(一)原理(二)应用场景(三)示例代码三、悲观锁(一)原理(二)应用场景(三)示例

java常见报错及解决方案总结

《java常见报错及解决方案总结》:本文主要介绍Java编程中常见错误类型及示例,包括语法错误、空指针异常、数组下标越界、类型转换异常、文件未找到异常、除以零异常、非法线程操作异常、方法未定义异常... 目录1. 语法错误 (Syntax Errors)示例 1:解决方案:2. 空指针异常 (NullPoi

Java反转字符串的五种方法总结

《Java反转字符串的五种方法总结》:本文主要介绍五种在Java中反转字符串的方法,包括使用StringBuilder的reverse()方法、字符数组、自定义StringBuilder方法、直接... 目录前言方法一:使用StringBuilder的reverse()方法方法二:使用字符数组方法三:使用自

Python依赖库的几种离线安装方法总结

《Python依赖库的几种离线安装方法总结》:本文主要介绍如何在Python中使用pip工具进行依赖库的安装和管理,包括如何导出和导入依赖包列表、如何下载和安装单个或多个库包及其依赖,以及如何指定... 目录前言一、如何copy一个python环境二、如何下载一个包及其依赖并安装三、如何导出requirem

Docker部署Jenkins持续集成(CI)工具的实现

《Docker部署Jenkins持续集成(CI)工具的实现》Jenkins是一个流行的开源自动化工具,广泛应用于持续集成(CI)和持续交付(CD)的环境中,本文介绍了使用Docker部署Jenkins... 目录前言一、准备工作二、设置变量和目录结构三、配置 docker 权限和网络四、启动 Jenkins

Rust格式化输出方式总结

《Rust格式化输出方式总结》Rust提供了强大的格式化输出功能,通过std::fmt模块和相关的宏来实现,主要的输出宏包括println!和format!,它们支持多种格式化占位符,如{}、{:?}... 目录Rust格式化输出方式基本的格式化输出格式化占位符Format 特性总结Rust格式化输出方式

Python中连接不同数据库的方法总结

《Python中连接不同数据库的方法总结》在数据驱动的现代应用开发中,Python凭借其丰富的库和强大的生态系统,成为连接各种数据库的理想编程语言,下面我们就来看看如何使用Python实现连接常用的几... 目录一、连接mysql数据库二、连接PostgreSQL数据库三、连接SQLite数据库四、连接Mo