当前位置: 首页 > 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…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

超短脉冲激光自聚焦效应

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

C++初阶-list的底层

目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

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

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

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

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

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