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

观察者模式全攻略:从设计原理到 SpringBoot 实践案例

观察者模式

观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都能得到通知并自动更新。

核心思想

观察者模式将**观察者(Observer)被观察者(Subject)**解耦,允许对象独立变化,并且当被观察者状态变化时,自动通知所有观察者。

观察者模式中的角色:

  1. Subject(被观察者):负责维护观察者列表,并在自身状态发生变化时通知所有观察者。它提供注册、移除和通知观察者的方法。
  2. Observer(观察者):定义一个接口,用于接收来自被观察者的通知。
  3. ConcreteSubject(具体被观察者):实现 Subject 接口,包含具体的状态,并在状态变化时调用 notifyObservers()
  4. ConcreteObserver(具体观察者):实现 Observer 接口,并在被观察者状态变化时更新自身。

观察者模式的 UML 原理类图

在这里插入图片描述

类图解释:

  1. Subject(被观察者接口)
    • 定义了方法 registerObserver()removeObserver()notifyObservers(),用于管理观察者的注册、移除和通知操作。
  2. Observer(观察者接口)
    • 定义了 update() 方法,观察者通过该方法接收来自被观察者的更新通知。
  3. ConcreteSubject(具体被观察者)
    • 维护一个观察者列表,并保存自身的状态。当状态发生变化时,调用 notifyObservers() 方法通知所有观察者。
    • 提供了 getState()setState() 方法来管理其状态,并在状态更新时调用通知方法。
  4. ConcreteObserver(具体观察者)
    • 持有对具体被观察者的引用,并实现 update() 方法,在被观察者状态变化时更新自身。

案例:天气预报系统 ☀️🌧️

场景说明

假设我们有一个天气预报系统,它实时监控天气数据,并向多个显示设备(如手机、电视、平板等)推送更新信息。系统中,气象站负责监控天气数据,当气温、湿度等信息发生变化时,它会通知所有的显示设备。这些设备会自动更新并显示最新的天气信息。

代码实现

Step 1: 定义 Observer 接口

// 观察者接口
public interface Observer {void update(float temperature, float humidity, float pressure);
}

Step 2: 定义 Subject 接口

// 被观察者接口
public interface Subject {void registerObserver(Observer observer);void removeObserver(Observer observer);void notifyObservers();
}

Step 3: 实现具体的 Subject

import java.util.ArrayList;
import java.util.List;// 具体的被观察者:天气数据
public class WeatherData implements Subject {private List<Observer> observers;private float temperature;private float humidity;private float pressure;public WeatherData() {observers = new ArrayList<>();}@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(temperature, humidity, pressure);  // 通知所有观察者}}// 当天气数据变化时,通知观察者public void setMeasurements(float temperature, float humidity, float pressure) {this.temperature = temperature;this.humidity = humidity;this.pressure = pressure;notifyObservers();  // 通知观察者}
}

Step 4: 实现具体的 Observer

PhoneDisplay 观察者

// 具体观察者:手机显示器
public class PhoneDisplay implements Observer {private float temperature;private float humidity;private float pressure;@Overridepublic void update(float temperature, float humidity, float pressure) {this.temperature = temperature;this.humidity = humidity;this.pressure = pressure;display();}public void display() {System.out.println("Phone Display - Temp: " + temperature + "°C, Humidity: " + humidity + "%, Pressure: " + pressure + "Pa");}
}

TVDisplay 观察者

// 具体观察者:电视显示器
public class TVDisplay implements Observer {private float temperature;private float humidity;private float pressure;@Overridepublic void update(float temperature, float humidity, float pressure) {this.temperature = temperature;this.humidity = humidity;this.pressure = pressure;display();}public void display() {System.out.println("TV Display - Temp: " + temperature + "°C, Humidity: " + humidity + "%, Pressure: " + pressure + "Pa");}
}

Step 5: 测试观察者模式

public class ObserverPatternDemo {public static void main(String[] args) {// 创建被观察者(天气数据)WeatherData weatherData = new WeatherData();// 创建观察者PhoneDisplay phoneDisplay = new PhoneDisplay();TVDisplay tvDisplay = new TVDisplay();// 注册观察者weatherData.registerObserver(phoneDisplay);weatherData.registerObserver(tvDisplay);// 模拟天气数据变化weatherData.setMeasurements(25.0f, 65.0f, 1013.0f);weatherData.setMeasurements(28.0f, 70.0f, 1010.0f);}
}

输出结果

Phone Display - Temp: 25.0°C, Humidity: 65.0%, Pressure: 1013.0Pa
TV Display - Temp: 25.0°C, Humidity: 65.0%, Pressure: 1013.0Pa
Phone Display - Temp: 28.0°C, Humidity: 70.0%, Pressure: 1010.0Pa
TV Display - Temp: 28.0°C, Humidity: 70.0%, Pressure: 1010.0Pa

Spring Boot 中使用观察者模式

Spring Boot 框架中,观察者模式主要可以通过 Spring 的事件驱动机制(Event Driven) 来实现。这是 Spring 框架对观察者模式的原生支持,允许不同的组件之间进行解耦通信,使得事件的发布者和监听者(观察者)可以独立变化。

Spring 事件驱动机制的核心概念:

  1. 事件(Event):类似于观察者模式中的 “Subject”(被观察者),当事件发生时,发布该事件。
  2. 事件监听器(Listener):类似于观察者,监听特定的事件并在事件发布时自动响应。
  3. 事件发布器(Publisher):发布事件,让所有监听器接收事件通知。

如何在 Spring Boot 中实现观察者模式:步骤详解**

Step 1: 创建自定义事件类

自定义事件类需要继承 Spring 提供的 ApplicationEvent 类。事件类可以封装一些需要传递的状态信息。

import org.springframework.context.ApplicationEvent;// 自定义事件类,继承 ApplicationEvent
public class CustomEvent extends ApplicationEvent {private String message;public CustomEvent(Object source, String message) {super(source);this.message = message;}public String getMessage() {return message;}
}
Step 2: 创建事件监听器

实现 ApplicationListener 接口,或使用注解 @EventListener 来创建监听器。监听器会在事件发布时自动被调用。

import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;// 事件监听器
@Component
public class CustomEventListener {// 使用 @EventListener 注解监听自定义事件@EventListenerpublic void handleCustomEvent(CustomEvent event) {System.out.println("Received event - " + event.getMessage());}
}
Step 3: 创建事件发布器

使用 ApplicationEventPublisher 来发布事件。当需要通知观察者时,可以发布自定义事件。

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;// 事件发布器
@Component
public class CustomEventPublisher {private final ApplicationEventPublisher publisher;public CustomEventPublisher(ApplicationEventPublisher publisher) {this.publisher = publisher;}// 发布事件public void publishEvent(String message) {CustomEvent event = new CustomEvent(this, message);publisher.publishEvent(event);  // 发布自定义事件}
}
Step 4: 使用事件发布器

在 Spring Boot 应用中,通过事件发布器发布事件,触发所有监听该事件的观察者。

@RestController
public class BasicController {@PostMapping("/publish")void publish(@RequestBody String message){eventPublisher.publishEvent(message);}}

输出结果

Received event - {"message": "hello"
}

Spring 事件驱动机制 VS 传统观察者模式

相似性:

  • 解耦:事件发布者(ApplicationEventPublisher)和事件监听器(ApplicationListener@EventListener)之间是解耦的,它们通过事件进行通信。
  • 一对多:一个事件可以被多个监听器同时监听,符合观察者模式的一对多依赖关系。

不同点:

  • 事件发布是异步的:Spring 的事件驱动机制允许事件的异步处理(如果配置了 @Async 注解),而传统的观察者模式通常是同步执行的。
  • 更加灵活的监听机制:Spring 提供了基于注解的 @EventListener,简化了监听器的注册过程,并可以使用条件过滤等高级功能。

Spring Boot 中,通过其内置的 事件驱动机制,可以轻松实现观察者模式。这种机制不仅保留了观察者模式的基本思想,还进一步增强了可扩展性和灵活性,支持异步处理、注解配置等高级特性。它在处理系统之间的解耦和事件驱动编程时尤其强大,非常适合使用在实际项目中。

使用观察者模式的典型场景:

  • 异步事件通知:如用户注册、邮件发送等需要异步处理的操作。
  • 解耦组件间的通信:模块化应用中,各模块之间的消息传递和事件处理。

总结

观察者模式 提供了一种解耦对象之间的依赖关系的方式,使得被观察者和观察者可以在不直接相互依赖的情况下进行通信。通过观察者模式,当一个对象发生变化时,所有依赖于它的对象都会自动收到通知并作出相应的处理。

相关文章:

观察者模式全攻略:从设计原理到 SpringBoot 实践案例

观察者模式 观察者模式&#xff08;Observer Pattern&#xff09;是一种行为型设计模式&#xff0c;它定义了一种一对多的依赖关系&#xff0c;使得当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都能得到通知并自动更新。 核心思想&#xff1a; 观察者模式将**观…...

【MyBatis】Java 数据持久层框架:认识 MyBatis

Java 数据持久层框架&#xff1a;认识 MyBatis 1.CRUD 注解2.映射注解3.高级注解3.1 高级注解3.2 MyBatis 3 注解的用法举例 MyBatis 和 JPA 一样&#xff0c;也是一款优秀的 持久层框架&#xff0c;它支持定制化 SQL、存储过程&#xff0c;以及高级映射。它可以使用简单的 XML…...

【Delphi】通过 LiveBindings Designer 链接控件示例

本教程展示了如何使用 LiveBindings Designer 可视化地创建控件之间的 LiveBindings&#xff0c;以便创建只需很少或无需源代码的应用程序。 在本教程中&#xff0c;您将创建一个高清多设备应用程序&#xff0c;该应用程序使用 LiveBindings 绑定多个对象&#xff0c;以更改圆…...

深度学习——基础知识

深度学习的重点在于优化&#xff0c;其中很重要的步骤在于如何调参&#xff0c;会涉及到一些微积分等数学知识。不同于以往接触到的数值运算&#xff0c;深度&#xff08;机器&#xff09;学习都是关于张量Tensor&#xff08;向量&#xff09;的计算&#xff0c;Python中最常用…...

QT实现升级进度条页面

一.功能说明 在Qt中实现固件升级的进度条显示窗口&#xff0c;你可以通过创建一个自定义的对话框&#xff08;Dialog&#xff09;来完成。这个对话框可以包含一个进度条&#xff08;QProgressBar&#xff09;、一些文本标签&#xff08;QLabel&#xff09;用于显示状态信息&am…...

JavaWeb--纯小白笔记04:Tomcat整合IDEA

IDEA整合Tomcat 1.点击Idea的导航栏里的Run&#xff0c;选择Edit Configurations 2.点击左上角的""&#xff0c;向下翻找到Tomcat Server 选择里面的Local 3.创建一个web工程&#xff0c;点击IDEA的File-->new-->project 然后选择Java Enterprise&#xff0c;…...

【jvm】动态链接为什么需要常量池

目录 1. 常量池的作用2. 动态链接与常量池的关系3. 动态链接的必要性 1. 常量池的作用 1.常量池是JVM&#xff08;Java虚拟机&#xff09;中用于存储字面量&#xff08;如字符串常量、整数常量等&#xff09;和符号引用&#xff08;如类和接口的完全限定名、字段的名称和描述符…...

HTTPS详解

文章目录 HTTPS加密 常见加密方式对称加密非对称加密非对称对称数据指纹 证书CA认证数字签名非对称证书对称 中间人 HTTPS 这也是一个应用层协议&#xff0c;是在HTTP协议的基础上引入了一个加密层 为什么要加密呢&#xff0c;这主要是因为如果不对传输主体加密&#xff0c;当…...

redis作为mybaits(mybatisplus)的缓存

引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency>配置application.yml文件 spring:data:redis:# 地址host: 127.0.0.1# 端口port: 6379# 数据…...

【环境配置】AST: Asymmetric Student-Teacher Networks for Industrial Anomaly Detection

文章目录 一、环境的配置二、预处理三、训练四、问题 一、环境的配置 # zheP04_cmp_AST $ conda create -n P04_cmp_AST python3.9 $ conda activate P04_cmp_AST $ conda install -y anaconda::scikit-learn $ conda install -y conda-forge::scipy $ conda install -y conda…...

TinkerTool System for Mac实用软件系统维护工具

TinkerTool System 是一款功能全面且强大的 Mac 实用软件&#xff0c;具有以下特点和功能&#xff1a; 软件下载地址 维护功能&#xff1a; 磁盘清理&#xff1a;能够快速扫描并清理系统中的垃圾文件、临时文件以及其他无用文件&#xff0c;释放宝贵的磁盘空间&#xff0c;保…...

物理学基础精解【9】

文章目录 直线与二元一次方程两直线夹角直线方程斜率两点式方程截距式方程将不同形式的直线方程转换为截距方程直线的一般方程直线一般方程的系数有一个或两个为零的直线 参考文献 直线与二元一次方程 两直线夹角 两直线 y 1 k 1 x b 1 , y 2 k 2 x b 2 形成夹角 a 1 和 a…...

Flask-JWT-Extended登录验证

1. 介绍 """安装:pip install Flask-JWT-Extended创建对象 初始化与app绑定jwt JWTManager(app) # 初始化JWTManager设置 Cookie 的选项:除了设置 cookie 的名称和值之外&#xff0c;你还可以指定其他的选项&#xff0c;例如&#xff1a;过期时间 (max_age)&…...

Altium Designer(AD)百度云下载与安装(附安装步骤)

在我们日常使用当中&#xff0c;Altium designer常常也被简称为AD&#xff0c;是一款一体化的电子产品开发系统软件&#xff0c;主要运行在Windows操作系统上。 我们通过Altium designer把原理图设计、电路仿真、PCB绘制编辑、拓扑逻辑自动布线、信号完整性分析和设计输出等技…...

无人机视角下的车辆数据集

车辆数据集 无人机视角下的车辆数据集。数据集为无人机俯拍的真实场景下的车辆机动车数据集。数据集已经标注好&#xff0c;yolo格式&#xff0c;txt标签。数据集已经划分好训练集&#xff08;20970张图片&#xff09;验证集&#xff08;5242张图片&#xff09;测试集&#xff…...

【MYSQL】聚合查询、分组查询、联合查询

目录 聚合查询聚合函数count()sum()avg()max()和min()总结 分组查询group by 子句having 子句 联合查询笛卡尔积内连接外连接自连接子查询单行子查询多行子查询from子句使用子查询 合并查询 聚合查询 聚合查询就是针对表中行与行之间的查询。 聚合函数 count() count(列名)&a…...

使用IDA Pro动态调试Android APP

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ 关于 android_server android_server 是 IDA Pro 在 Android 设备上运行的一个调试服务器。 通过在 Android 设备上运行android_server&#xff0c;IDA Pro …...

JS中的for...in和for...of有什么区别?

你好&#xff0c;我是沐爸&#xff0c;欢迎点赞、收藏、评论和关注。 在 JavaScript 中&#xff0c;for...in 和 for...of 是两种用于遍历数组&#xff08;或其他可迭代对象&#xff09;的循环语句&#xff0c;但它们之间存在显著的差异。 一、遍历数组 for…in const arr …...

【C++篇】引领C++模板初体验:泛型编程的力量与妙用

文章目录 C模板编程前言第一章: 初始模板与函数模版1.1 什么是泛型编程&#xff1f;1.1.1 为什么要有泛型编程&#xff1f;1.1.1 泛型编程的优势 1.2 函数模板的基础1.2.1 什么是函数模板&#xff1f;1.2.2 函数模板的定义格式1.2.3 示例&#xff1a;通用的交换函数输出示例&am…...

在react中 使用redux

1.安装redux npm install reduxjs/toolkit react-redux 2.创建切片模块化数据 在Src目录下创建store目录&#xff0c;创建moude目录 创建tab.js import { createSlice } from reduxjs/toolkit; const tabSlice createSlice({name: tab,initialState: {Collapse: false,},re…...

计算机毕业设计python+spark知识图谱房价预测系统 房源推荐系统 房源数据分析 房源可视化 房源大数据大屏 大数据毕业设计 机器学习

《PythonSpark知识图谱房价预测系统》开题报告 一、研究背景与意义 随着城市化进程的加速和房地产市场的不断发展&#xff0c;房价成为影响人们生活质量的重要因素之一。准确预测房价不仅有助于政府制定科学的房地产政策&#xff0c;还能为开发商提供市场参考&#xff0c;同时…...

Spring-bean的生命周期-终篇

阶段8&#xff1a;Bean属性设置阶段 属性设置阶段分为3个小的阶段 实例化后阶段Bean属性赋值前处理Bean属性赋值 实例化后阶段 这里也有spring给我们预留了扩展&#xff0c;就是实现InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation方法&#xff0c;开发…...

Kotlin 枚举和 when 表达式(六)

导读大纲 1.1 表示和处理选择: Enums和when1.1.1 声明枚举类和枚举常量1.1.2 使用 when 表达式处理枚举类 1.1 表示和处理选择: Enums和when 在本节中,我们将以在 Kotlin 中声明枚举为例,介绍 when 结构 when可以被视为比 Java 中 switch 结构更强大、更常用的替代品 1.1.1 …...

数字范围按位与

优质博文&#xff1a;IT-BLOG-CN 题目 给你两个整数left和right&#xff0c;表示区间[left, right]&#xff0c;返回此区间内所有数字 按位与 的结果&#xff08;包含left、right端点&#xff09;。 示例 1&#xff1a; 输入&#xff1a;left 5, right 7 输出&#xff1a;…...

WebRTC编译后替换libwebrtc.aar时提示找不到libjingle_peerconnection_so.so库

Loading native library: jingle_peerconnection_so 问题原因&#xff1a;编译的时候只编译了armeabi-v7a的版本&#xff0c;但是应用程序是arm64-v8a&#xff0c;所以无法运行 解决方法&#xff1a;更新编译脚本&#xff0c;加上arm64-v8a进行编译 ./tools_webrtc/android/bu…...

Nature Electronics |无感佩戴的纤维基电子皮肤(柔性半导体器件/柔性健康监测/电子皮肤/柔性传感/纤维器件)

英国剑桥大学Yan Yan Shery Huang课题组,在《Nature Electronics 》上发布了一篇题为“Imperceptible augmentation of living systems with organic bioelectronic fibres”的论文,第一作者为王文宇博士(Wenyu Wang),论文内容如下: 一、 摘要 利用电子技术对人类皮肤和…...

深入剖析Docker容器安全:挑战与应对策略

随着容器技术的广泛应用&#xff0c;Docker已成为现代应用开发和部署的核心工具。它通过轻量级虚拟化技术实现应用的隔离与封装&#xff0c;提高了资源利用率。然而&#xff0c;随着Docker的流行&#xff0c;其安全问题也成为关注焦点。容器化技术虽然提供了良好的资源隔离&…...

后端技术打怪升级之路

记录后端技术打怪升级之路&#xff0c;如下是个人总记的主要技术栈&#xff0c;仅供参考&#xff01; 备注&#xff1a; 同名文章一同步发表于个人网站及微信公众号 个人网站 工藤新一的技术小窝...

Leetcode 3296. Minimum Number of Seconds to Make Mountain Height Zero

Leetcode 3296. Minimum Number of Seconds to Make Mountain Height Zero 1. 解题思路2. 代码实现 题目链接&#xff1a;3296. Minimum Number of Seconds to Make Mountain Height Zero 1. 解题思路 这一题的思路的话我们采用的是一个二分法的思路&#xff0c;找到一个最大…...

计算机毕业设计之:基于深度学习的路面检测系统(源码+部署文档+讲解)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…...