软件设计模式系列之二十一——观察者模式

1 观察者模式的定义

观察者模式(Observer Pattern)是一种行为型设计模式,它允许对象之间建立一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。这个模式也被称为发布-订阅模式,因为它模拟了一个主题(发布者)与多个观察者(订阅者)之间的关系。

观察者模式主要用于实现对象之间的解耦,使得被观察者(主题)和观察者之间的交互更加灵活。它是一种广泛应用于软件开发中的设计模式,常见于图形界面开发、事件处理系统和分布式系统中。

2 举例说明

为了更好地理解观察者模式,让我们考虑一个实际的例子:天气站。假设我们有一个天气站应用程序,用户可以订阅该应用程序以获取实时天气更新。在这个场景中,天气站就是被观察者(主题),而订阅天气更新的用户就是观察者(订阅者)。
在这里插入图片描述

当天气站收到新的天气数据时,它会通知所有订阅者,以便它们可以更新显示当前天气的界面。这种方式使得用户可以实时获取最新的天气信息,而无需反复查询。

3 结构

观察者模式的结构包括以下几个要素:
在这里插入图片描述

Subject(主题):主题是被观察的对象,它维护一组观察者,提供方法来添加和删除观察者,并在状态发生变化时通知观察者。
ConcreteSubject(具体主题):具体主题是主题的具体实现,它包含了真正的状态和状态变化逻辑。
Observer(观察者):观察者是订阅主题的对象,它定义了一个更新接口,以便主题在状态变化时通知观察者。
ConcreteObserver(具体观察者):具体观察者是观察者的具体实现,它实现了更新接口,以便在接收到通知时执行相应的操作。

4 实现步骤

观察者模式的实现步骤如下:

创建主题接口(Subject),定义添加、删除和通知观察者的方法。
创建具体主题类(ConcreteSubject),实现主题接口,并维护观察者列表和状态变量。
创建观察者接口(Observer),定义更新方法。
创建具体观察者类(ConcreteObserver),实现观察者接口,并定义具体的更新逻辑。
在客户端中创建主题对象和观察者对象,将观察者注册到主题上。
当主题的状态发生变化时,调用主题的通知方法,通知所有注册的观察者。
观察者接收到通知后,执行相应的更新操作。

5 代码实现(Java)

让我们通过一个简单的 Java 代码示例来演示观察者模式的实现。

// Step 1: 创建主题接口
interface Subject {void addObserver(Observer observer);void removeObserver(Observer observer);void notifyObservers();
}// Step 2: 创建具体主题类
class WeatherStation implements Subject {private List<Observer> observers = new ArrayList<>();private String weatherData;@Overridepublic void addObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(weatherData);}}public void setWeatherData(String data) {this.weatherData = data;notifyObservers();}
}// Step 3: 创建观察者接口
interface Observer {void update(String data);
}// Step 4: 创建具体观察者类
class User implements Observer {private String name;public User(String name) {this.name = name;}@Overridepublic void update(String data) {System.out.println(name + " 收到天气更新:" + data);}
}// Step 5: 客户端代码
public class Main {public static void main(String[] args) {WeatherStation weatherStation = new WeatherStation();User user1 = new User("Alice");User user2 = new User("Bob");weatherStation.addObserver(user1);weatherStation.addObserver(user2);weatherStation.setWeatherData("晴天");weatherStation.setWeatherData("下雨");}
}

在上面的示例中,WeatherStation 是具体主题,User 是具体观察者。当天气发生变化时,WeatherStation 通知所有注册的观察者,观察者执行相应的更新操作。

6 典型应用场景

观察者模式在许多应用场景中都得到了广泛的应用,包括以下一些场景:

股票市场:投资者可以订阅股票价格的变化。一旦股票价格发生变化,所有订阅了该股票的投资者都会立即收到通知,以便他们可以做出及时的投资决策。
在这里插入图片描述

社交媒体:社交媒体平台中,用户可以关注其他用户的动态。当被关注用户发布新的动态、照片或视频时,关注者会收到通知,以便互动和评论。

库存管理:在库存管理系统中,订阅者可以订阅特定商品的库存变化。当库存数量发生变化时,订阅者可以收到通知,帮助他们及时补充库存或采取其他措施。

观察者模式将主题和观察者解耦,使主题可以轻松通知多个观察者,而观察者可以根据自己的需求选择订阅感兴趣的主题。这种模式提高了系统的灵活性和可扩展性,使信息传递更加高效和及时

7 优缺点

观察者模式的优点包括:

解耦性:被观察者和观察者之间的关系是松散耦合的,可以独立地改变它们中的任何一个,而不会影响其他部分。
可扩展性:可以轻松地添加新的观察者,扩展系统功能。
通知机制:观察者能够实时获取到被观察者的状态变化,无需主动轮询。
可维护性:代码易于维护和理解,因为逻辑分散在各个观察者中。

观察者模式的缺点包括:

如果观察者过多,通知所有观察者可能会导致性能问题。
如果观察者之间有依赖关系,可能会引入复杂性。
如果不正确地实现,可能会导致循环引用。

8 类似模式

观察者模式建立了一种一对多的依赖关系,其中一个对象(被观察者)维护一组依赖它的对象(观察者),并在状态变化时通知观察者。与观察者模式类似的模式有以下几种,它们在某些方面具有相似性,但也存在一些区别:

委托模式(Delegate Pattern):

委托模式也允许一个对象委托给多个对象,类似于观察者模式中的通知多个观察者。 在委托模式中,被委托的对象通常不知道委托它的对象,而观察者模式中,被观察者知道它的观察者并主动通知它们。委托模式通常用于事件处理和回调机制,而观察者模式用于状态变化通知。

策略模式(Strategy Pattern):

策略模式和观察者模式都关注对象之间的交互,但在策略模式中,可以根据需要切换不同的算法或行为,而观察者模式关注对象状态的变化通知。观察者模式通常用于对象之间的一对多关系,而策略模式用于定义一组可互换的算法,客户端可以在运行时选择其中一个算法。

命令模式(Command Pattern):

命令模式和观察者模式都涉及到将请求发送给接收者对象,但观察者模式关注状态变化的通知,而命令模式关注封装请求成对象。在观察者模式中,被观察者通知观察者状态的改变,而在命令模式中,客户端创建命令对象并将其发送给接收者,接收者执行命令。

这些模式都有共同点,即它们都有助于降低对象之间的耦合度,并提供了一种松散的交互方式。然而,它们的重点和用途有所不同,因此在设计应用程序时,需要根据具体需求选择最合适的模式。

9 小结

观察者模式是一种有用的设计模式,它可以帮助我们实现对象之间的松散耦合,使系统更加灵活和可扩展。通过定义一对多的依赖关系,观察者模式允许被观察者在状态变化时通知所有观察者,实现了一种高效的通知机制。在实际应用中,观察者模式可以用于各种领域,包括图形界面开发、事件处理系统、消息队列和实时数据更新等。要成功使用观察者模式,需要谨慎设计接口和类,并确保正确地管理观察者的注册和通知。

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

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

相关文章

ChatGPT架构师:语言大模型的多模态能力、幻觉与研究经验

来源 | The Robot Brains Podcast OneFlow编译 翻译&#xff5c;宛子琳、杨婷 9月26日&#xff0c;OpenAI宣布ChatGPT新增了图片识别和语音能力&#xff0c;使得ChatGPT不仅可以进行文字交流&#xff0c;还可以给它展示图片并进行互动&#xff0c;这是一次ChatGPT向多模态进化的…

React 入门笔记

前言 国庆值班把假期拆了个稀碎, 正好不用去看人潮人海, 趁机会赶个晚集入门一下都火这么久的 React 前端技术. 话说其实 n 年前也了解过一丢丢来着, 当时看到一上来就用 JS 写 DOM 的套路直接就给吓退了, 扭头还去看 Vue 了&#x1f923;, 现在从市场份额来看, 确实 React 还…

【开发篇】十、Spring缓存:手机验证码的生成与校验

文章目录 1、缓存2、用HashMap模拟自定义缓存3、SpringBoot提供缓存的使用4、手机验证码案例完善 1、缓存 缓存是一种介于数据永久存储介质与数据应用之间的数据临时存储介质使用缓存可以有效的减少低速数据读取过程的次数&#xff08;例如磁盘IO&#xff09;&#xff0c;提高…

83、SpringBoot --- 下载和安装 MSYS2、 Redis

启动redis服务器&#xff1a; 打开小黑窗&#xff1a; C:\Users\JH>e: E:>cd E:\install\Redis6.0\Redis-x64-6.0.14\bin E:\install\Redis6.0\Redis-x64-6.0.14\bin>redis-server.exe redis.windows.conf 启动redis客户端&#xff1a; 小黑窗&#xff1a;redis-cli …

ICMP差错包

ICMP报文分类 Type Code 描述 查询/差错 0-Echo响应 0 Echo响应报文 查询 3-目的不可达 0 目标网络不可达报文 差错 1 目标主机不可达报文 差错 2 目标协议不可达报文 差错 3 目标端口不可达报文 差错 4 要求分段并设置DF flag标志报文 差错 5 源路由…

坠落防护 挂点装置

声明 本文是学习GB 30862-2014 坠落防护 挂点装置. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了高处坠落防护挂点装置的技术要求、检验方法、检验规则及标识。 本标准适用于防护高处坠落的挂点装置。 本标准不适用于体育及消…

PL/SQL+cpolar公网访问内网Oracle数据库

文章目录 前言1. 数据库搭建2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射 3. 公网远程访问4. 配置固定TCP端口地址4.1 保留一个固定的公网TCP端口地址4.2 配置固定公网TCP端口地址4.3 测试使用固定TCP端口地址远程Oracle 前言 Oracle&#xff0c;是甲骨文公司的一款关系…

java导出word(含图片、表格)

1.pom 引入 <!--word报告生成依赖--><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.2</version></dependency><dependency><groupId>org.apache.poi</groupI…

Web 中间件怎么玩?

本次主要是聊聊关于 web 中间件&#xff0c; 分为如下四个方面 什么是 web 框架中间件 为什么要使用 web 中间件 如何使用及其原理 哪些场景需要使用中间件 开门见山 web 中间件是啥 Web 框架中的中间件主要指的是在 web 请求到具体路由之前或者之后&#xff0c;会经过一个或…

第1篇 目标检测概述 —(4)目标检测评价指标

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。目标检测评价指标是用来衡量目标检测算法性能的指标&#xff0c;可以分为两类&#xff0c;包括框级别评价指标和像素级别评价指标。本节课就给大家重点介绍下目标检测中的相关评价指标及其含义&#xff0c;希望大家学习之后…

FPGA project : rom_vga_jump

只有vga_pix 模块代码与rom_vga不同&#xff0c;所以只上传了这个模块的代码与仿真代码。 // #define BLACK 0x0000 // 黑色 // #define NAVY 0x000F // 深蓝色 // #define DGREEN 0x03E0 // 深绿色 // #define DCYAN …

Java集合处理Stream流使用解析

Stream Stream是Java 8引入的一个新的API&#xff0c;用于处理集合数据的流式操作。它提供了一种更简洁、更灵活的方式来处理集合数据&#xff0c;可以实现更高效的数据处理和转换。 使用Stream&#xff0c;可以通过一系列的操作来对集合数据进行筛选、映射、排序、聚合等操作…

在Qt中,怎么获取到在mainwindow.ui文件中添加的控件

2023年9月30日&#xff0c;周六晚上 假设我在mainwindow.ui中添加了一个名为textEdit的QTextEdit对象 在mainwindow.cpp中&#xff0c;可以通过ui对象来获取到这个控件

让大脑自由

前言 作者写这本书的目的是什么&#xff1f; 教会我们如何让大脑更好地为自己工作。 1 大脑的运行机制是怎样的&#xff1f; 大脑的基本运行机制是神经元之间通过突触传递信息&#xff0c;神经元的兴奋和抑制状态决定了神经网络的运行和信息处理&#xff0c;神经网络可以通过…

【图像分割】图像检测(分割、特征提取)、各种特征(面积等)的测量和过滤(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

系统集成|第二十一章(笔记)

目录 第二十一章 知识产权与法律法规21.1 知识产权21.2 法律法规 上篇&#xff1a;第二十章、收尾管理 第二十一章 知识产权与法律法规 21.1 知识产权 概述&#xff1a;狭义的知识产权就是传统意义上的知识产权&#xff0c;包括著作权&#xff08;含邻接权&#xff09;&#x…

iOS自动化测试方案(二):Xcode开发者工具构建WDA应用到iphone

文章目录 一、环境准备1.1、软件环境1.2、硬件环境1.3、查看版本 二、安装WDA过程2.7、构建失败&#xff0c;这类错误有很多&#xff0c;比如在选择开发者账号后&#xff0c;就会提示:Failed to register bundle identifier表示应用唯一注册失败2.9、第二个错误&#xff0c;完全…

嵌入式Linux应用开发-第十四章查询方式的按键驱动程序

嵌入式Linux应用开发-第十四章查询方式的按键驱动程序 第十四章 查询方式的按键驱动程序_编写框架14.1 LED驱动回顾14.2 按键驱动编写思路14.3 编程&#xff1a;先写框架14.3.1 把按键的操作抽象出一个button_operations结构体14.3.2 驱动程序的上层&#xff1a;file_operation…

Oracle的递归公共表表达式

查询节点id为2的所有子节点的数据&#xff0c;包括向下级联 WITH T1 (id, parent_id, data) AS (SELECT id, parent_id, dataFROM nodesWHERE id 2UNION ALLSELECT t.id, t.parent_id, t.dataFROM nodes tJOIN T1 n ON t.parent_id n.id ) SELECT * FROM T1; --建表语句 C…