Spring框架之观察者模式 (Observer Pattern)

观察者模式(Observer Pattern)详解

观察者模式(Observer Pattern)是一种行为型设计模式,用于定义对象间的一种 一对多 的依赖关系,使得当一个对象的状态发生改变时,其相关依赖对象能够自动接收到通知并进行相应的更新。观察者模式广泛应用于事件驱动的系统中,是 GUI 应用程序、事件系统、消息推送等场景中的核心设计模式。

1. 观察者模式的定义

1.1 什么是观察者模式?

观察者模式,也称为 发布-订阅模式(Publish-Subscribe Pattern),其核心思想是 “观察者订阅被观察者”。当被观察者(也称为 主题(Subject))的状态发生变化时,所有已订阅的观察者(Observer)都会收到通知,并根据通知做出相应的反应。

1.2 观察者模式的结构

观察者模式通常包含以下几个角色:

  1. Subject(被观察者/主题)
    • 维护一个观察者列表。
    • 提供注册、注销观察者的方法。
    • 当状态改变时,通知所有观察者。
  2. Observer(观察者)
    • 定义一个更新接口,用于接收通知。
  3. ConcreteSubject(具体被观察者)
    • 继承 Subject,实现具体的通知逻辑。
  4. ConcreteObserver(具体观察者)
    • 继承 Observer,实现具体的响应逻辑。

2. 观察者模式的类图

+-----------------+        +----------------+
|   Subject       |<>----->|   Observer     |
+-----------------+        +----------------+
| + attach()      |        | + update()     |
| + detach()      |        +----------------+
| + notify()      |              ^
+-----------------+              |
       ^                         |
       |                         |
+-----------------+        +--------------------+
| ConcreteSubject |        | ConcreteObserver   |
+-----------------+        +--------------------+
| - state         |        | - observerState    |
| + getState()    |        | + update()         |
| + setState()    |        +--------------------+
+-----------------+

3. 观察者模式的实现

以下是一个简单的观察者模式示例。在该示例中,假设有一个天气站(WeatherStation)作为被观察者,多个显示设备(DisplayDevice)作为观察者,天气站会将温度变化通知给所有已注册的显示设备。

3.1 Java 示例代码
import java.util.ArrayList;
import java.util.List;

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

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

// 具体的被观察者:天气站
class WeatherStation implements Subject {
    private List<Observer> observers;
    private float temperature;

    public WeatherStation() {
        this.observers = new ArrayList<>();
    }

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temperature);
        }
    }

    // 设置新的温度并通知观察者
    public void setTemperature(float temperature) {
        this.temperature = temperature;
        notifyObservers();
    }
}

// 具体的观察者:手机显示设备
class PhoneDisplay implements Observer {
    private String name;

    public PhoneDisplay(String name) {
        this.name = name;
    }

    @Override
    public void update(float temperature) {
        System.out.println(name + " 显示温度更新为: " + temperature + "°C");
    }
}

// 具体的观察者:平板显示设备
class TabletDisplay implements Observer {
    @Override
    public void update(float temperature) {
        System.out.println("平板设备显示温度更新为: " + temperature + "°C");
    }
}

// 测试客户端
public class ObserverPatternDemo {
    public static void main(String[] args) {
        // 创建被观察者(天气站)
        WeatherStation weatherStation = new WeatherStation();

        // 创建观察者
        PhoneDisplay phoneDisplay = new PhoneDisplay("手机设备1");
        TabletDisplay tabletDisplay = new TabletDisplay();

        // 注册观察者
        weatherStation.registerObserver(phoneDisplay);
        weatherStation.registerObserver(tabletDisplay);

        // 更新天气并通知观察者
        weatherStation.setTemperature(25.5f);
        weatherStation.setTemperature(30.0f);

        // 移除一个观察者
        weatherStation.removeObserver(phoneDisplay);
        weatherStation.setTemperature(28.5f);
    }
}

输出结果

手机设备1 显示温度更新为: 25.5°C
平板设备显示温度更新为: 25.5°C
手机设备1 显示温度更新为: 30.0°C
平板设备显示温度更新为: 30.0°C
平板设备显示温度更新为: 28.5°C

4. 观察者模式的应用场景

观察者模式广泛应用于各种需要事件通知的场景中:

  1. GUI 事件监听
    • 在图形用户界面中,如按钮点击、文本框输入变化等事件处理机制。
  2. MVC 架构
    • 在 MVC 设计模式中,视图(View)会观察模型(Model)的变化,当模型的数据发生变化时,视图会自动更新。
  3. 推送通知系统
    • 应用程序中的消息推送服务、实时更新、订阅发布系统(如 RSS、社交媒体通知)。
  4. 缓存刷新机制
    • 当缓存数据源发生变化时,通知所有相关缓存进行刷新。
  5. 数据库触发器
    • 在数据库中,当某个表的数据发生变化时,可以触发通知其他表或系统。

5. 观察者模式的优缺点

5.1 优点
  • 降低耦合度:被观察者和观察者之间是松耦合关系。被观察者无需知道观察者的具体实现,符合“依赖倒置原则”。
  • 支持广播通信:一个被观察者可以同时通知多个观察者,扩展性强。
  • 符合开闭原则:可以在不修改被观察者的情况下添加新的观察者,实现系统的灵活扩展。
5.2 缺点
  • 潜在的性能问题:如果有大量的观察者,通知所有观察者可能会带来一定的性能开销。
  • 通知顺序不确定:观察者的通知顺序是不确定的,可能会导致数据不一致的情况。
  • 内存泄漏:如果观察者没有正确注销,可能会导致内存泄漏,尤其是在 Java 等需要手动管理观察者注册和注销的语言中。

6. 观察者模式的扩展

6.1 推模型 vs 拉模型
  • 推模型(Push Model)
    • 被观察者主动将变更数据推送给观察者。适用于数据量小、变化频繁的场景。
  • 拉模型(Pull Model)
    • 被观察者仅通知观察者状态已发生变化,观察者自行拉取所需的数据。适用于数据量大、变化不频繁的场景。
6.2 Java 内置的观察者模式

Java 标准库提供了 java.util.Observable 类和 java.util.Observer 接口来实现观察者模式。

示例

import java.util.Observable;
import java.util.Observer;

class NewsAgency extends Observable {
    private String news;

    public void setNews(String news) {
        this.news = news;
        setChanged(); // 标记状态已改变
        notifyObservers(news);
    }
}

class NewsChannel implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("新闻频道收到新闻更新: " + arg);
    }
}

public class JavaObserverExample {
    public static void main(String[] args) {
        NewsAgency newsAgency = new NewsAgency();
        NewsChannel newsChannel = new NewsChannel();

        newsAgency.addObserver(newsChannel);
        newsAgency.setNews("新冠疫情最新动态!");
    }
}

输出

新闻频道收到新闻更新: 新冠疫情最新动态!
6.3 RxJava 的响应式编程
  • 在响应式编程中,观察者模式的思想被广泛应用。RxJava 通过 ObservableObserver 提供了更加灵活和功能丰富的 API 来处理异步数据流。

7. 总结

观察者模式是一种非常常用的设计模式,在许多场景下都能提升系统的扩展性和灵活性。它不仅降低了对象之间的耦合度,还能实现事件驱动的机制,使得系统能够动态响应外部的变化。

  • 优点:松耦合、易于扩展、支持广播通信。
  • 缺点:可能导致性能开销、内存泄漏风险。
  • 适用场景:事件监听、推送通知、MVC 设计模式、数据缓存机制。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

告别系统限制,一键关闭Windows Defender

作为一款专业级系统优化工具&#xff0c;Defender Remover 为追求完全系统控制权的高级用户提供了全方位的安全组件管理解决方案。这款强大的实用工具不仅完美支持从 Windows 8.x 到最新的 Windows 11 全系列操作系统&#xff0c;更提供了精细化的安全组件调整选项。 本工具最…

GitLab 如何降级?

本分分享 GitLab 降级的流程和注意事项。极狐GitLab 为 GitLab 的中文发行版&#xff0c;本文以私有化部署的极狐GitLab 为例来演示整个过程。 【极狐GitLab 推出 GitLab 老旧版本的专业升级服务【https://dl.gitlab.cn/cm33bsfv】&#xff0c;可以让 12.x、13.x、14.x、15.x …

微软日志丢失事件敲响安全警钟

NEWS | 事件回顾 最近&#xff0c;全球最大的软件公司之一——微软&#xff0c;遭遇了一场罕见的日志丢失危机。据报告&#xff0c;从9月2日至9月19日&#xff0c;持续长达两周的时间里&#xff0c;微软的多项核心云服务&#xff0c;包括身份验证平台Microsoft Entra、安全信息…

leetcode268 丢失的数字

class Solution { public:int missingNumber(vector<int>& nums) {sort(nums.begin(),nums.end());int i0;for(;i<nums.size();i){if(i!nums[i]) break;}return i;} }; sort(nums.begin(), nums.end()); 对数组进行排序。虽然排序是一个可行的方法&#xff0c;但是…

HBuilder(uniapp) 配置android模拟器

HBuilder&#xff08;uniapp&#xff09; 配置android模拟器 选择完成之后&#xff0c;点击ok&#xff0c;再次点击Configure—》AVD Manager

Redis高可用-主从复制

这里写目录标题 Redis主从复制主从复制过程环境搭建从节点配置常见问题主从模式缺点 Redis主从复制 虽然 Redis 可以实现单机的数据持久化&#xff0c;但无论是 RDB 也好或者 AOF 也好&#xff0c;都解决不了单点宕机问题&#xff0c;即一旦 redis 服务器本身出现系统故障、硬…

Vue3 -- 项目配置之husky【企业级项目配置保姆级教程4】

引言&#xff1a; eslint&#xff1a;代码规范校验prettier&#xff1a;代码格式化stylelint&#xff1a;CSS代码校验 上述三篇文章集成配置完成代码校验工具&#xff0c;当时需要每次手动的去执行命令才会格式化我们的代码。。如果有人没有格式化就提交了远程仓库&#xff0…

PaddlePaddle 开源产业级文档印章识别PaddleX-Pipeline “seal_recognition”模型 开箱即用篇(一)

AI时代到来&#xff0c;各行各业都在追求细分领域垂直类深度学习模型&#xff0c;今天给大家介绍一个PaddlePaddle旗下&#xff0c;基于PaddleX Pipeline 来完成印章识别的模型“seal_recognition”。 官方地址&#xff1a;https://github.com/PaddlePaddle/PaddleX/blob/relea…

06.VSCODE:备战大项目,CMake专项配置

娇小灵活的简捷配置不过是年轻人谈情说爱的玩具&#xff0c;帝国大厦的构建&#xff0c;终归要交给CMake去母仪天下。一个没有使用 CMake 的 C 项目&#xff0c;就像未来世界里的一台相声表演&#xff0c;有了德纲却无谦&#xff0c;观众笑着遗憾。—— 语出《双城记》作者&…

新高考志愿录取方式变革,如何应对挑战?答案在这里

在教育改革的浪潮中&#xff0c;新高考的实施带来了重大变革&#xff0c;其中志愿录取方式的变化尤为关键。它不仅关系着每一位考生的未来发展&#xff0c;更是对整个教育体系产生着深远影响。今天&#xff0c;我们就来深入探讨新高考的两大志愿录取方式&#xff0c;分析其特点…

Unity网络通信(part7.分包和黏包)

目录 前言 概念 解决方案 具体代码 总结 分包黏包概念 分包 黏包 解决方案概述 前言 在探讨Unity网络通信的深入内容时&#xff0c;分包和黏包问题无疑是其中的关键环节。以下是对Unity网络通信中分包和黏包问题前言部分的详细解读。 概念 在网络通信中&#xff0c;…

64位PE壳编写指南

文章目录 前记x64壳后记reference 文章首发于微信公众号《渗透测试安全攻防》 前记 开源的关于PE压缩和加密壳几乎都是32位&#xff0c;于是学习写一个64位的壳供参考&#xff0c;其原理差别不大学写PE壳是熟悉PE结构很好的方式项目已开源&#xff0c;求个stars嘻嘻嘻 https:…

3D意识(3D Awareness)浅析

一、简介 3D意识&#xff08;3D Awareness&#xff09;主要是指视觉基础模型&#xff08;visual foundation models&#xff09;对于3D结构的意识或感知能力&#xff0c;即这些模型在处理2D图像时是否能够理解和表示出图像中物体或场景的3D结构&#xff0c;其具体体现在编码场景…

Web安全之SQL注入---基础

文章目录 SQL注入简介SQL注入基础SQL注入分类SQL注入流程 SQL注入简介 什么是SQL注入&#xff1f; SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严&#xff0c;攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句&#xff0c;在管理…

黄仁勋对话孙正义:日本的AI新饼、Arm的AI野心与英伟达的东亚新机会

2020 年的软银世界大会上&#xff0c;孙正义与黄仁勋围绕「What’s Next for AI」展开了一次围炉对谈。黄仁勋穿着标志性的皮夹克坐在火堆旁&#xff0c;畅谈了将 Arm 纳入麾下的重要价值&#xff0c;孙正义也毫不吝啬赞美之词&#xff0c;称老黄在未来 10 年会达到史蒂夫 乔布…

【案例】Excel使用宏来批量插入图片

一、场景介绍 我有一个excel文件&#xff0c;需要通过一列的文件名称&#xff0c;按照规则给批量上传图片附件。 原始文件&#xff1a; 成功后文件&#xff1a; 二、实现方法 1. 使用【wps】工具打开Excel文件&#xff0c;将其保存为启用宏的文件。 2.找到编辑宏的【VB编辑器…

Kubernetes-ArgoCD篇-01-简介

1、什么是Argo CD Argo CD 是针对 Kubernetes 的声明式 GitOps 持续交付工具。 Argo CD官方文档地址&#xff1a;https://argo-cd.readthedocs.io Argo CD源码地址&#xff1a;https://github.com/argoproj/argo-cd 1.1 关于Argo Argo是一个开源的项目&#xff0c;主要是扩…

odoo17 前端 在头像下拉 dropdown 自定义菜单

odoo17 前端 在头像下拉 dropdown 自定义菜单 其实很简单, 我们先找到原来已经创建好的, 找到代码位置 使用 我的资料 为例 odoo-17.0\addons\hr\static\src\user_menu\my_profile.js /** odoo-module **/import { _t } from "web/core/l10n/translation"; import …

时序预测 | Python基于CNN-transformer时间序列预测

时序预测 | Python基于CNN-transformer时间序列预测 目录 时序预测 | Python基于CNN-transformer时间序列预测预测效果基本介绍参考资料 预测效果 基本介绍 时序预测 | Python基于CNN-transformer时间序列预测 Cnn-transformer-自适应稀疏自注意力ASSA-对比归一化contranorm预…

(干货)Jenkins使用kubernetes插件连接k8s的认证方式

#Kubernetes插件简介 Kubernetes 插件的目的是能够使用 Kubernetes 配合&#xff0c;实现动态配置 Jenkins 代理&#xff08;使用 Kubernetes 调度机制来优化负载&#xff09;&#xff0c;在执行 Jenkins Job 构建时&#xff0c;Jenkins Master 会在 kubernetes 中创建一个 Sla…