设计模式|观察者模式(Observer Pattern)

文章目录

  • 初识观察者模式
  • 优缺点
  • 示例代码(使用 Java 实现)
  • 有哪些知名的框架采用了观察者模式
  • 常见面试题

初识观察者模式

观察者模式(Observer Pattern)是一种软件设计模式,属于行为型模式。它定义了一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。观察者模式也被称为发布-订阅(Publish-Subscribe)模式。在观察者模式中,有两种核心角色:

  1. Subject(主题):它是被观察的对象,它维护一组依赖于它的观察者,并提供添加、删除和通知观察者的方法。
  2. Observer(观察者):它是依赖于主题的对象,当主题状态发生变化时,观察者会得到通知并进行相应的更新。

优缺点

观察者模式的优点包括:

  • 松耦合:主题和观察者之间的关系是松耦合的,使得它们可以相互独立地变化。
  • 可扩展性:可以方便地增加新的观察者,或者修改现有的观察者,而不需要修改主题的代码。
  • 通知机制:观察者只需要订阅主题,一旦主题状态改变,它们就会自动收到通知,无需手动轮询。

观察者模式虽然有许多优点,但也存在一些缺点,包括:

  • 内存泄漏风险:如果观察者未正确移除,或者被持续添加,可能导致内存泄漏问题。因为主题会持有对观察者的引用,如果观察者在不再需要时没有被正确移除,那么观察者将会一直存在于主题的观察者列表中,从而无法被垃圾回收。
  • 性能问题:当主题有大量观察者时,通知所有观察者可能会影响性能,特别是在需要频繁更新的情况下。因为每次状态改变时,都需要遍历观察者列表并通知它们,这可能会导致性能开销。
  • 可能导致意外更新:观察者模式的设计使得主题的状态改变会导致所有观察者的更新。如果观察者之间存在依赖关系,可能会导致意外的更新序列或循环更新,从而引发不必要的复杂性和错误。
  • 主题状态传递困难:当主题需要将状态传递给观察者时,可能会面临一些挑战。因为通知观察者时通常只会传递简单的通知,而不会传递更多的上下文信息。这可能需要观察者主动查询主题以获取更多的信息,从而增加了系统的复杂性。
  • 不适合异步处理:观察者模式通常是同步的,主题状态改变后会立即通知观察者进行更新。这在某些情况下可能会导致问题,特别是在需要异步处理的情况下,例如需要将状态更新推送到远程服务器时,同步通知可能会导致性能问题或阻塞。

总的来说,观察者模式在一些场景下是非常有用的,但在应用时需要注意以上缺点,以避免可能的问题。
观察者模式在实际应用中被广泛采用,例如在 GUI 开发中,当用户与界面交互时,界面可以作为主题,而控制器或其他对象则可以作为观察者,从而实现界面和业务逻辑的解耦。

示例代码(使用 Java 实现)

import java.util.ArrayList;
import java.util.List;// 主题接口
interface Subject {void registerObserver(Observer observer);void removeObserver(Observer observer);void notifyObservers();
}// 具体主题类
class ConcreteSubject implements Subject {private List<Observer> observers = new ArrayList<>();private int state;public int getState() {return state;}public void setState(int state) {this.state = state;notifyObservers();}@Overridepublic void registerObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update();}}
}// 观察者接口
interface Observer {void update();
}// 具体观察者类
class ConcreteObserver implements Observer {private ConcreteSubject subject;public ConcreteObserver(ConcreteSubject subject) {this.subject = subject;subject.registerObserver(this);}@Overridepublic void update() {System.out.println("State updated: " + subject.getState());}
}// 测试
public class ObserverPatternExample {public static void main(String[] args) {ConcreteSubject subject = new ConcreteSubject();ConcreteObserver observer1 = new ConcreteObserver(subject);ConcreteObserver observer2 = new ConcreteObserver(subject);// 修改主题状态,观察者将会得到通知并更新subject.setState(5);}
}

在上面的示例中,ConcreteSubject是一个具体的主题类,它维护了一个状态,并且具有注册、移除观察者和通知观察者的方法。ConcreteObserver是一个具体的观察者类,它实现了观察者接口,并在构造函数中注册到主题中。通过修改主题的状态,观察者会自动更新。

有哪些知名的框架采用了观察者模式

在后端开发和中间件领域,有一些知名的框架或中间件采用了观察者模式,以下是其中的一些例子:

  1. Spring Framework: Spring 框架中的事件机制就是基于观察者模式实现的。当应用程序中的某些事件发生时,例如上下文加载、Bean 初始化完成等,Spring 会发布相应的事件通知,而监听器(观察者)则可以订阅这些事件并执行相应的操作。
  2. Node.js: 虽然 Node.js 在前端开发中更为知名,但它也被广泛应用于后端开发。Node.js 中的事件驱动模型就是基于观察者模式实现的。EventEmitter 类充当主题,而事件监听器则充当观察者,当特定事件发生时,EventEmitter 会通知所有注册的监听器进行处理。
  3. Apache Kafka: Kafka 是一个分布式流处理平台,也是一个消息中间件。它的消息订阅和发布机制就是基于观察者模式实现的。生产者将消息发布到 Kafka 的主题(topic),而消费者则订阅这些主题,当消息到达时,Kafka 会通知所有订阅了该主题的消费者进行消费。
  4. RabbitMQ: RabbitMQ 是一个开源的消息队列中间件,它也使用了观察者模式。生产者将消息发送到消息队列,而消费者则订阅队列并接收消息,当消息到达时,RabbitMQ 会通知所有订阅了该队列的消费者进行消费。
  5. Django 框架: Django 是一个 Python 的后端 Web 框架,它的信号机制就是基于观察者模式实现的。当某些特定事件发生时(如保存对象前后、用户登录等),Django 会发送信号通知,而信号接收器则可以订阅这些信号并执行相应的处理逻辑。

这些都是在后端开发和中间件领域中广泛使用的框架或中间件,它们都使用了观察者模式来实现事件驱动和消息通知等功能。
观察者模式是非常常用的设计模式,它描述了对象一对多依赖关系下,如何通知并更新的机制,这种机制可以用在前端的 UI 与数据映射、后端的请求与控制器映射,平台间的消息通知等大部分场景,无论现实还是程序中,存在依赖且需要通知的场景非常普遍。

常见面试题

在面试中,可能会遇到以下与观察者模式相关的问题,以及相应的答案:

  1. 请解释观察者模式是什么?
    答案: 观察者模式是一种软件设计模式,它定义了一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。
  2. 观察者模式中的核心角色有哪些?
    答案: 观察者模式中有两个核心角色:主题(Subject)和观察者(Observer)。主题维护一组依赖于它的观察者,并提供添加、删除和通知观察者的方法;而观察者则依赖于主题,当主题状态发生变化时,观察者会得到通知并进行相应的更新。
  3. 观察者模式和发布-订阅模式有何区别?
    答案: 观察者模式和发布-订阅模式(Pub-Sub)都涉及到对象间的消息通信,但它们之间有一些区别。观察者模式中,主题对象直接通知观察者对象,而发布-订阅模式中,发布者和订阅者之间通过消息代理或中间件进行通信,发布者不直接与订阅者通信。
  4. 如何避免在观察者模式中可能出现的内存泄漏问题?
    答案: 内存泄漏问题可能出现在观察者模式中,特别是在观察者没有正确移除时。为了避免这种问题,可以在主题中使用弱引用来持有观察者,或者在观察者不再需要时手动将其从主题中移除。
  5. 观察者模式的优缺点是什么?
    答案: 观察者模式的优点包括松耦合、可扩展性和通知机制;而缺点包括内存泄漏风险、性能问题、可能导致意外更新等。
  6. 请列举一个实际应用中观察者模式的例子。
    答案: 一个实际应用中观察者模式的例子是电子商务网站中的库存管理系统。库存管理系统是主题,而订单系统、仓库系统等则是观察者,当某个商品的库存数量发生变化时,库存管理系统会通知所有依赖它的观察者更新相关信息,如商品的可售数量、是否需要补货等。
  7. 观察者模式在哪些框架或中间件中得到了应用?
    答案: 观察者模式在许多框架和中间件中得到了应用,例如 Java 的 Swing/AWT、Spring Framework、Node.js、Apache Kafka、RabbitMQ 等。

这些问题可以帮助面试者深入了解观察者模式的概念、应用和实现细节,展现其对软件设计模式的理解和应用能力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/771781.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

仿mudo库实现高并发服务器实现文章整合

相关文章实现与转载 (按实际项目流程发布) 时间轮设计-CSDN博客 正则表达式的使用-CSDN博客 bind函数的认识与基本使用-CSDN博客 timerfd的认识与基本使用-CSDN博客 Buffer缓冲区类实现(模块一)-CSDN博客 日志打印宏的编写-CSDN博客 Socket套接字类实现(模块二)-CSDN博…

C#语言规范及特殊用法笔记

前言 记录在学习C#过程中遇到的知识点&#xff0c;会持续更新。 1. 常用数据类型结构的默认值 创建类的一个实例时&#xff0c;在执行构造函数之前&#xff0c;如果没给成员变量赋初始值&#xff0c;C#编译器将每一个成员变量初始化为默认值。虽然C#编译器为每个类型都设置了…

MySQL 8.0.35 企业版开启审计audit log功能

一、系统环境和要求 在MySQL中&#xff0c;开启日志审计可以记录数据库的操作日志&#xff0c;包括修改、删除、插入等操作。这对于追踪和分析数据库的使用情况以及排查潜在的安全问题非常有帮助。本文将详细介绍如何开启MySQL的日志审计功能。 操作系统&#xff1a;Ubuntu 20…

人工智能 框架 paddlepaddle 飞桨 使用指南 使用例子 线性回归模型demo 1

安装过程&使用指南&线性回归模型 使用例子 本来预想 是安装 到 conda 版本的 11.7的 但是电脑没有gpu 所以 安装过程稍有变动,下面简单讲下 conda create -n paddle_env117 python=3.9 由于想安装11.7版本 py 是3.9 所以虚拟环境名称也是 paddle_env117 activa…

6 Spring-AOP

文章目录 1&#xff0c;AOP简介1.1 什么是AOP?1.2 AOP作用1.3 AOP核心概念 2&#xff0c;AOP入门案例2.1 需求分析2.2 思路分析2.3 环境准备2.4 AOP实现步骤步骤1:添加依赖步骤2:定义接口与实现类步骤3:定义通知类和通知步骤4:定义切入点步骤5:制作切面步骤6:将通知类配给容器…

数据库SQLSever——数据查询

一、无条件查询 查询表的所有信息 SELECT * FROM 表名 例&#xff1a;查询学生表 SELECT * FROM student087 二、根据列名查询 根据列名查询表信息 SELECT [列名],[列名],.... FROM 表名 例&#xff1a;查询学生表的学生学号和姓名 SELECT SNO&#xff0c;SNAME FROM STU…

OD_2024_C卷_100分_70、停车场车辆统计【JAVA】【逻辑分析】

题目描述 特定大小的停车场&#xff0c;数组cars[]表示&#xff0c;其中1表示有车&#xff0c;0表示没车。 车辆大小不一&#xff0c;小车占一个车位&#xff08;长度1&#xff09;&#xff0c;货车占两个车位&#xff08;长度2&#xff09;&#xff0c;卡车占三个车位&#…

常用设计模式介绍

前言 简说设计模式。 文章目录 前言一、设计模式的要素1、设计模式解决的问题2、设计模式分类1&#xff09;创建型设计模式2&#xff09;结构型设计模式3&#xff09;行为型设计模式 二、详细介绍1、创建型设计模式1&#xff09;工厂方法模式2&#xff09;抽象工厂模式3&#x…

基于FPGA的光纤通信系统设计

文章目录 光纤通信系统的组成发送端FPGA端口定义状态机设计代码示例 接收端功能模块端口定义状态机设计 光纤通信系统的组成 发送端FPGA 发送控制逻辑、数据编码、校验码生成、缓存控制、时钟控制 端口定义 状态机设计 代码示例 接收端功能模块 接收端控制逻辑、数据解码、…

谈谈伦敦银投资的价值吗?

白银作为贵金属家族中的一员&#xff0c;当然有着其自身的经济价值和投资价值&#xff0c;尤其是在通货膨胀或货币贬值的时候&#xff0c;伦敦银的价格往往会上涨&#xff0c;投资者参与其中就能起到保值增值的作用。 此外&#xff0c;白银还是一种很好的避险资产&#xff0c;…

AST学习三---构造节点

题目:将 var a 3; 通过AST替换成 var a 12; 本次所用到的知识 1.path.replaceWith (单)节点替换函数,调用方式 path.replaceWith(newNode); 实参一般是node类型,即将当前遍历的path替换为实参里的新节点 注意,它不能用于Array的替换,即实参不能是Array的类型 2.babel/…

突破编程_C++_STL教程( copy 算法)

1 std::copy 算法的概念与用途 std::copy 是 C 标准库中的一种算法&#xff0c;主要用于将一个范围内的元素从一个位置复制到另一个位置。其函数原型如下&#xff1a; template<class InputIterator, class OutputIterator> OutputIterator copy(InputIterator first…

电商api数据接口开发亚马逊国际按关键字搜索商品API请求key接入演示

要使用亚马逊国际API按关键字搜索商品&#xff0c;你需要使用item_search请求。首先&#xff0c;你需要注册一个开发者账号并获取API密钥&#xff08;API Key和API Secret&#xff09;。然后&#xff0c;你可以使用以下Python代码示例来按关键字搜索商品&#xff1a; # coding…

港大新工作 HiGPT:一个模型,任意关系类型 !

论文标题&#xff1a; HiGPT: Heterogeneous Graph Language Model 论文链接&#xff1a; https://arxiv.org/abs/2402.16024 代码链接&#xff1a; https://github.com/HKUDS/HiGPT 项目网站&#xff1a; https://higpt-hku.github.io/ 1. 导读 异质图在各种领域&#xf…

Linux系统下安装部署Linux管理面板1panel

目录 一 1panel介绍 1、1Panel简介 2、1Panel特点 二、本地环境规划 1、本此实验目的 2、本地环境部署 三、部署1Panel&#xff08;在线安装&#xff09; 1.创建安装目录 2.一键部署1Panel 3.检查1Panel服务运行状态 4.检查1Panel监听端口 四、关闭防火墙和selinux…

zabbix进阶

知识点补充 zabbix server在主机上运行服务&#xff0c;端口号为10050&#xff0c;zabbix agent 在被监控机器上运行&#xff08;源码下载&#xff09;主要完成对cpu&#xff0c;磁盘的信息采集&#xff0c;端口号为10051 zabbix 软件结构组成&#xff1a; 1.Zabbix Web GUI …

leetcode 107.二叉树的层序遍历II

题目 思路 正常层序遍历输出&#xff1a; [[3],[9,20],[15,7]] 这道题要求的输出&#xff1a;[[15,7],[9,20],[3]] 可以观察到&#xff0c;只要我们把原来的结果reverse一下就行了。 代码 //leetcode submit region begin(Prohibit modification and deletion)import java…

HWY-41B无源静态电压继电器 整定范围19-240VAC导轨安装JOSEF约瑟

HWY-31A无辅源静态电压继电器 HWY-32A无辅源静态电压继电器 HWY-33A无辅源静态电压继电器 HWY-34A无辅源静态电压继电器 HWY-35A无辅源静态电压继电器 HWY-31B无辅源静态电压继电器 HWY-32B无辅源静态电压继电器 HWY-33B无辅源静态电压继电器 HWY-34B无辅源静态电压继电器 HW…

激活函数选得好,模型性能差不了!17个方法,让网络训练更高效

激活函数是神经网络中不可或缺的组成部分&#xff0c;它们通过引入非线性特性&#xff0c;增强了网络的表达能力和学习能力。常用的激活函数主要可以分为两大类&#xff1a;饱和激活函数、非饱和激活函数。其中sigmoid和tanh是饱和激活函数&#xff0c;而ReLU及其变体则是非饱和…

3月25日,每日信息差

&#x1f396; 素材来源官方媒体/网络新闻 &#x1f384; 京东汽车将和小米汽车进行深度合作 &#x1f30d; 百度将为苹果国行iPhone16提供AI功能&#xff1f;百度方面称暂无回应 &#x1f30b; 国产结核病新型mRNA疫苗即将问世 &#x1f381; 美国发布严重地磁暴预警&#xff…