【重温设计模式】观察者模式及其Java示例

news2024/11/14 18:50:35

观察者模式的概念和原理

在编程世界中,设计模式作为一种解决问题的策略,它的存在就如同人类语言中的成语,是一种经过时间考验的有效解决方案。

观察者模式就是其中一种重要的设计模式,它在很多场景中都有着广泛的应用。那么,什么是观察者模式呢?观察者模式,又被称为发布-订阅模式,其基本概念是定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。

它的设计原理就像是一场戏,主角(主题)在舞台上表演,观众(观察者)在台下观看。当主角的表演发生变化时,观众能立即感知到这种变化。在编程领域,观察者模式的应用场景十分广泛,比如GUI中的事件处理,社交网络中的消息推送,甚至是股票交易系统中的价格更新等等。

class OneMoreSubject {
    private List<Observer> observers = new ArrayList<>();

    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    public void notifyAllObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

以上是一个简单的观察者模式的Java代码示例,OneMoreSubject类就是我们的主题,它维护了一个观察者列表。当有新的观察者加入时,我们通过addObserver方法将其加入到观察者列表中。当主题的状态发生变化时,我们通过notifyAllObservers方法通知所有的观察者。这样,我们就实现了观察者模式的基本框架。接下来,我们将详细解释观察者模式的主要组成部分,包括主题(Subject)和观察者(Observer),并解释它们的角色和互动方式。

观察者模式的组成部分

在探讨观察者模式的具体应用之前,我们首先需要理解它的主要组成部分。观察者模式主要由两个角色构成,它们分别是主题(Subject)和观察者(Observer)。主题可以被视为数据的提供者,它持有一些重要的状态信息。当这些状态发生变化时,主题会通知所有的观察者。观察者则是数据的接收者,它们订阅了主题,并在主题状态变化时接收通知。主题与观察者之间的关系,就像是一份报纸与它的订阅者,或者是一个B站UP主与它的关注者。

public interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}

public interface Observer {
    void update(OneMore oneMore);
}

在这个简单的Java代码示例中,Subject接口声明了注册(register)、移除(remove)和通知(notify)观察者的方法,而Observer接口则声明了一个更新(update)方法,用于接收主题的状态变化通知。这就是观察者模式的基本构成,通过这种方式,我们可以将数据的提供者和接收者解耦,使得在数据状态变化时,可以灵活地通知到所有关注此变化的观察者。

有了对观察者模式组成部分的理解,我们就可以进一步探讨如何在实际项目中应用观察者模式了。在下一部分,我们将通过一个电子商务系统的Java实例,展示观察者模式的工作流程。

观察者模式的Java实例

在我们刚刚探讨过的观察者模式的主要组成部分——主题(Subject)和观察者(Observer)之后,现在让我们通过一个具体的Java实例来看看观察者模式是如何在实际项目中发挥作用的。假设我们正在开发一个电子商务系统,当一个商品的库存数量发生变化时,需要通知相关的销售人员和采购人员,这就是一个典型的观察者模式的应用场景。

首先,我们定义一个Subject类,这个类有一个OneMore的商品库存数量,当这个数量发生变化时,就需要通知所有的观察者。

public class Subject {
    private int OneMore;
    private List<Observer> observers = new ArrayList<>();

    public void setOneMore(int OneMore) {
        this.OneMore = OneMore;
        notifyAllObservers();
    }

    public void attach(Observer observer){
        observers.add(observer);      
    }

    public void notifyAllObservers(){
        for (Observer observer : observers) {
            observer.update();
        }
    } 
}

然后,我们定义一个Observer接口和两个实现这个接口的类:SalesObserverPurchaseObserver,分别代表销售人员和采购人员。

public interface Observer {
    void update();
}

public class SalesObserver implements Observer {
    public void update() {
        System.out.println("SalesObserver: OneMore's stock has changed.");
    }
}

public class PurchaseObserver implements Observer {
    public void update() {
        System.out.println("PurchaseObserver: OneMore's stock has changed.");
    }
}

OneMore的库存数量发生变化时,Subject类就会调用notifyAllObservers方法,通知所有的观察者。这样,无论是销售人员还是采购人员,都能够得到库存变化的通知,从而做出相应的行动。这就是观察者模式的工作流程。

implements
implements
contains
1
*
Subject
-int OneMore
-List<Observer> observers
+setOneMore(int OneMore)
+attach(Observer observer)
+notifyAllObservers()
«interface»
Observer
+update()
SalesObserver
+update()
PurchaseObserver
+update()

然而,任何设计模式都有其适用的场景,也有其优缺点。接下来,我们将探讨观察者模式的优缺点,以及在何种情况下应该使用观察者模式。

观察者模式的优缺点

在我们深入探讨观察者模式的优缺点之前,让我们先来描绘一下这种模式的特色。观察者模式是一种行为设计模式,它允许对象在状态发生变化时通知其依赖对象,而无需它们之间直接耦合。这种模式的主要优点是它支持单向依赖,这意味着主题并不关心观察者的具体实现,只关心观察者是否遵循了预定义的接口。这种设计大大提高了代码的灵活性和可重用性。

然而,这种模式也有其缺点。首先,观察者模式可能导致过度通信。当主题的状态发生改变时,所有的观察者都会被通知,即使他们对该变化没有任何兴趣。其次,如果观察者和主题之间存在循环依赖,可能会导致系统陷入无限循环。最后,如果观察者的处理时间过长,可能会阻塞主题的进程。

对于何时使用观察者模式,一般的建议是当你希望在对象的状态改变时,能够通知其他对象,但又不希望这些对象之间存在直接依赖关系时,可以考虑使用观察者模式。例如,一个邮件订阅系统就可以使用观察者模式,当新的邮件到达时,所有订阅者都会收到通知。

总结

总的来说,观察者模式是一种强大的设计模式,它能够帮助我们在系统中实现松耦合的对象间通信。通过这种模式,我们可以使得一个对象的状态变化能够通知到其他的对象,而不需要这些对象之间存在直接的联系。这样,我们就可以实现对象间的动态交互,使得系统更加灵活和可扩展。

但是,我们也需要注意,观察者模式并不是万能的。在某些情况下,它可能会导致过度通信,或者造成系统的循环依赖。因此,我们在使用观察者模式时,需要仔细考虑其适用性,确保它能够帮助我们解决问题,而不是引入新的问题。

我们可能会遇到许多需要使用观察者模式的场景。比如,我们可能需要实现一个社交网络的消息推送系统,或者一个电子商务网站的库存管理系统。在这些场景中,观察者模式都能够发挥其强大的作用。

然而,设计模式只是工具,而不是目标。我们的最终目标,是通过使用这些工具,来编写出高效、可维护、可扩展的代码。因此,我们应该根据实际的需求和场景,灵活地选择和使用设计模式,而不是死板地套用。

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

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

相关文章

自然语言处理: 第十七章RAG的评估技术RAGAS

论文地址&#xff1a;[2309.15217] RAGAS: Automated Evaluation of Retrieval Augmented Generation (arxiv.org) 项目地址: explodinggradients/ragas: Evaluation framework for your Retrieval Augmented Generation (RAG) pipelines (github.com) 上一篇文章主要介绍了R…

【论文阅读笔记】Split frequency attention network for single image deraining

1.论文介绍 Split frequency attention network for single image deraining 用于单幅图像去噪的分频注意力网络 Paper Code 2023年 SIVP 2.摘要 雨纹对图像质量的影响极大&#xff0c;基于数据驱动的单图像去噪方法不断发展并取得了巨大的成功。然而&#xff0c;传统的卷积…

7大结构型设计模式

结构性设计模式是软件工程中常用的一类设计模式。 作用&#xff1a;主要用于处理类或对象之间的组合以实现更灵活、可扩展和可维护的代码结构。 这些模式通常涉及到类和对象之间的静态组合关系&#xff0c;以及如何将它们组织在一起以满足特定的设计目标。 结构型模式有&#x…

git设置别名及查看别名

设置别名 git config --global alias.lg "具体的参数"git config --global alias.lg "log --dateformat:%Y/%m/%d %H:%M:%S --prettyformat:%C(yellow)%h%C(reset) %C(bold blue)%ad%C(reset) %an %C(green)%s%C(reset)"查看别名 git config --list | fi…

新能源汽车小三电系统

小三电系统 新能源电动汽车的"小三电"系统&#xff0c;一般指车载充电机(OBC)、车载 DC/DC 变换器&#xff0c;和高压直流配电盒(PDU)。一辆纯电动汽车一般配备一台OBC 和一台车载 DC/DC 变换器。OBC将外部输入的交流电转化为直流电输出给电池&#xff0c;DC/DC衔接…

数据可视化实战(二)

将每个城市在每个月份平均PM2.5绘制成折线图 import pandas as pd import matplotlib.pyplot as plt df pd.read_excel(./PM2.5.xlsx)display(df.head(10)) df.shape # (161630, 15)城市年份月份日期小时季节PM2.5露点湿度压强温度风向累计风速降水量累计降水量0北京2010112…

总结mac下解决matplotlib中文显示问题的几种方法

一、前言&#xff1a; 使⽤matplotlib画图时&#xff0c;由于matplotlib默认没有中⽂&#xff0c;显⽰中文时会出现空⽩⼩⽅块。 二、方法&#xff1a; 2.1 matplotlib中使用SimHei字体 1&#xff09;进入终端后查看matplotlib的字体路径&#xff1a; $ python >>&g…

机器学习-04-分类算法-04-支持向量机SVM

总结 本系列是机器学习课程的系列课程&#xff0c;主要介绍机器学习中分类算法&#xff0c;本篇为分类算法与SVM算法部分。 本门课程的目标 完成一个特定行业的算法应用全过程&#xff1a; 懂业务会选择合适的算法数据处理算法训练算法调优算法融合 算法评估持续调优工程化…

Qt5.14.2 深入理解Qt多线程编程,掌握线程池架构实现高效并发

在高并发的软件系统中&#xff0c;多线程编程是解决性能瓶颈和提高系统吞吐量的有效手段。作为跨平台的应用程序开发框架&#xff0c;Qt为我们提供了强大的多线程支持。本文将深入探讨Qt多线程编程的实现细节&#xff0c;并介绍线程池的设计思想&#xff0c;帮助读者彻底掌握Qt…

Pytorch常用的函数(七)空洞卷积详解

Pytorch常用的函数(七)空洞卷积详解 1 初识空洞卷积 1.1 空洞卷积与语义分割任务 语义分割面临的困境&#xff1a; 与检测模型类似&#xff0c;语义分割模型也是建立是分类模型基础上的&#xff0c;即利用CNN网络来提取特征进行分类。在CNN分类模型中&#xff0c;一般情况下…

鸿蒙开发 一 (一)、框架了解

一、UI框架 开发范式名称 语言生态 UI更新方式 适用场景 适用人群 声明式开发范式 ArkTS语言 数据驱动更新 复杂度较大、团队合作度较高的程序 移动系统应用开发人员、系统应用开发人员 类Web开发范式 JS语言 数据驱动更新 界面较为简单的程序应用和卡片 Web前端…

2025张宇考研数学基础36讲,视频百度网盘+PDF

一、张宇老师全年高数体系&#xff08;听课用书指南&#xff09; 25张宇全程&#xff1a; docs.qq.com/doc/DTmtOa0Fzc0V3WElI 复制粘贴在浏览器上打开&#xff0c;就可以看到2025张宇的全部的啦&#xff01; 一般来说我们把考研数学划分为3-4个阶段&#xff0c;分别是基础阶…

详解基于快速排序算法的qsort的模拟实现

目录 1. 快速排序 1.1 快速排序理论分析 1.2 快速排序的模拟实现 2. qsort的模拟实现 2.1 qsort的理论分析 2.2 qsort的模拟实现 qsort函数是基于快速排序思想设计的可以针对任意数据类型的c语言函数。要对qsort进行模拟实现&#xff0c;首先就要理解快速排序。 1. 快…

【物联网应用】基于云计算的智能化温室种植一体化平台

目录 第一章 作品概述 1.1. 作品名称 1.2. 应用领域 1.3.主要功能 1.4.创新性说明 第二章 需求分析 2.1 现实背景 2.2 用户群体及系统功能 2.3 竞品分析 第三章 技术方案 3.1. 硬件组成与来源 3.2. 硬件设计合理性 3.3. 硬件系统设计图 3.4. 接口的通用性与可扩展性 3.5. 代码规…

【已解决】在pycharm终端无法激活conda环境,但在cmd命令行中可以

一、问题描述 在windows下winr启动cmd命令行&#xff0c;可以成功运行conda命令并且激活环境在pycharm中打开Terminal终端&#xff0c;发现无法运行conda和pip命令&#xff0c;报错环境无法激活 无法在管道中间运行文档: D:\software\Anaconda3\condabin\conda.bat。 所在位置…

uniapp+vue3+setup语法糖开发微信小程序时不能定义globalData的解决方法

在使用 uniapp 开发小程序的时候&#xff0c; 发现使用了setup 语法糖 &#xff0c;定义 globalData 时&#xff0c;要不是定义不了&#xff0c; 要不就是使用 getApp()取不到&#xff0c;后来想到一个不伦不类的方法解决了&#xff0c; 这个方法有点难看&#xff0c; 但是解决…

云手机的数据安全有保障吗?

随着移动互联网的迅速发展&#xff0c;云手机作为一种新兴的移动终端技术&#xff0c;正在逐渐受到人们的关注和应用。然而&#xff0c;对于云手机而言&#xff0c;数据安全问题一直是人们关注的焦点之一。本文将探讨云手机的数据安全性&#xff0c;并分析其是否具备足够的保障…

每周编辑精选|微软开源 Orca-Math 高质量数学数据集、清华大学研究团队发布条件去噪扩散模型 SPDiff...

Orca-Math 是微软研究院发布的数学推理模型&#xff0c;该模型展示了较小的专业模型在特定领域的价值&#xff0c;它们可以匹配甚至超越更大模型的性能。微软近期开源了用于训练 Orca-Math 的 Orca-Math-200K 数学单词问题数据集&#xff0c;现已在 hyper.ai 官网提供下载&…

记录对NSIS的一些微调 实现Electron安装包美化

利洽科技-nsNiuniuSkinUI - NSIS 实现了electron 的安装包美化&#xff0c;免费&#xff0c;便捷。 下面我整理了一些关于它的微调&#xff0c;使其安装卸载更加简单快捷。 1. 默认展示安装路径部分 &#xff08;1&#xff09;将moreconfiginfo标签visible 设置为 true&#…

const,static深度总结——c++穿透式分析

前言&#xff1b;c类和对象的知识点中除了几种默认函数&#xff0c; 比较重要的还有使用const和static修饰成员相关知识点。const在c中特性很简单。 但是在使用中&#xff0c; 比较容易疏忽大意出现问题。 static特性也很简单&#xff0c; 但是比起const来要直接的多。 在使用中…