设计模式——观察者模式

文章目录

  • 1 概述
  • 2 实现
  • 3 总结

1 概述

观察者模式可以分为观察者和被观察者,观察者通过注册到一个被观察者中,也可视为订阅,当被观察者的数据发生改变时,会通知到观察者,观察者可以据此做出反应。
可以类比订阅报纸,报社就是被观察者,订阅者就是观察者,订阅者通过订阅报纸与报社建立联系,而报社有新报纸则主动投递给订阅者。

2 实现

这里以Head First 设计模式中的观察者模型为例。
在这里插入图片描述
讲的是一个气象监测站模型,气象站有三个传感器,分别采集温度、湿度和气压三个值。气象站采集完数据之后会将数据设置到WeatherData对象中,而WeatherData数据更新后需要同时将数据更新到三个显示装置中。
这里就是使用了观察者模式,WeatherData是数据中心,是被观察者,而显示装置则是观察者,当观察者订阅之后,数据中心的变化都会主动通知到观察者。
这个模型的类图如下:
在这里插入图片描述
其中最重要的就是Subject和Observer接口,这里Subject就是被观察者的总接口,而Observer接口则是观察者总接口。Display接口则是因为多个显示器都拥有共同的Display行为。
WeatherData实现Subject,成为一个具体的Subject,而三个Display则实现Observer接口,成为观察者实例。
下面是代码实例:
Subject接口

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

拥有对Observer对象操作的注册和删除操作,也有通知各个Observer的方法。
Observer接口

public interface Observer {void update(float temperature, float humidity, float pressure);
}

观察者接口,拥有Observer的公用操作,Subject通过该接口来更新各个Observer中的数据。被观察者其实就是通过这个接口来通知到各个观察者的
DisplayElement接口

public interface DisplayElement {public void display();
}

各个Display的公用方法
WeatherData类

public class WeatherData implements Subject {private List<Observer> observers;private float temperature;private float humidity;private float pressure;public WeatherData() {observers = new ArrayList<Observer>();}public void registerObserver(Observer o) {observers.add(o);}public void removeObserver(Observer o) {observers.remove(o);}public void notifyObservers() {for (Observer observer : observers) {observer.update(temperature, humidity, pressure);}}public void measurementsChanged() {notifyObservers();}public void setMeasurements(float temperature, float humidity, float pressure) {this.temperature = temperature;this.humidity = humidity;this.pressure = pressure;measurementsChanged();}public float getTemperature() {return temperature;}public float getHumidity() {return humidity;}public float getPressure() {return pressure;}}

具体的被观察者类,会有一个存有所有观察者对象的集合,当数据变化时,会遍历这个集合来通知观察者,而通知就是调用观察者的update方法。
ForecastDisplay类

public class ForecastDisplay implements Observer, DisplayElement {private float currentPressure = 29.92f;  private float lastPressure;private WeatherData weatherData;public ForecastDisplay(WeatherData weatherData) {this.weatherData = weatherData;weatherData.registerObserver(this);}public void update(float temp, float humidity, float pressure) {lastPressure = currentPressure;currentPressure = pressure;display();}public void display() {System.out.print("Forecast: ");if (currentPressure > lastPressure) {System.out.println("Improving weather on the way!");} else if (currentPressure == lastPressure) {System.out.println("More of the same");} else if (currentPressure < lastPressure) {System.out.println("Watch out for cooler, rainy weather");}}
}

这是三个具体的观察者其中的一个,实现了Observer接口,并持有WeatherData对象,在ForecastDisplay对象创建的时候,会将自己加到WeatherData被观察者对象的集合中保存。当数据变化时,WeatherData会从集合中遍历到这个对象,并调用其update方法。
其他三个观察者类似。
测试代码:

public class WeatherStation {public static void main(String[] args) {WeatherData weatherData = new WeatherData();CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);weatherData.setMeasurements(80, 65, 30.4f);weatherData.setMeasurements(82, 70, 29.2f);weatherData.setMeasurements(78, 90, 29.2f);weatherData.removeObserver(forecastDisplay);weatherData.setMeasurements(62, 90, 28.1f);}
}

三个观察者显示器获取到了同样的更新数据,但是他们可以根据自身的显示逻辑来做出不同的显示结果

Current conditions: 80.0F degrees and 65.0% humidity
Avg/Max/Min temperature = 80.0/80.0/80.0
Forecast: Improving weather on the way!
Current conditions: 82.0F degrees and 70.0% humidity
Avg/Max/Min temperature = 81.0/82.0/80.0
Forecast: Watch out for cooler, rainy weather
Current conditions: 78.0F degrees and 90.0% humidity
Avg/Max/Min temperature = 80.0/82.0/78.0
Forecast: More of the same
Current conditions: 62.0F degrees and 90.0% humidity
Avg/Max/Min temperature = 75.5/82.0/62.0Process finished with exit code 0

3 总结

  1. 观察者加被观察者组成观察者模式
  2. 观察者继承Observer接口,该接口提供一个通知观察者的方法
  3. 观察者持有被观察者的引用,在构造方法中调用被观察者的注册方法将自身注册为一个观察者
  4. 被观察者拥有一个观察者集合,用于存储所有注册的观察者的对象
  5. 观察者可以自己调用注册和注销方法将自身添加到被观察者的列表中或从列表中移除
  6. 被观察者要通知观察者时,遍历观察者集合,调用观察者接口中的方法通知观察者

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

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

相关文章

vue3+ts+elementui-plus二次封装弹框

一、弹框组件BaseDialog <template><div classmain><el-dialog v-model"visible" :title"title" :width"dialogWidth" :before-close"handleClose"><!-- 内容插槽 --><slot></slot><template…

每天一个linux小技巧

1.nohup no hang up&#xff0c;用nohup运行命令可以使命令永久的执行下去&#xff0c;和用户终端没有关系&#xff0c;例如我们断开SSH连接都不会影响他的运行&#xff0c;注意了nohup没有后台运行的意思。 加&的作用是将&#xff0c;命令放到后台运行&#xff0c;使得终端…

【Docker】Consul的容器服务更新与发现

目录 一、Consul二、什么是服务注册与发现1.2什么是consul1.3consul提供的一些关键特性 二、Consul部署2.1环境配置2.2Consul服务器配置1. 建立 Consul 服务2. 查看集群信息3. 通过 http api 获取集群信息 2.3 registrator服务器配置1. 安装 Gliderlabs/Registrator2. 测试服务…

代码随想录算法训练营第四十九天|动态规划part10|● 121. 买卖股票的最佳时机 ● 122.买卖股票的最佳时机II

● 121. 买卖股票的最佳时机 Best Time to Buy and Sell Stock - LeetCode dp[i][0] 持有股票得到的最大现金 dp[i][1] 不持有股票得到的最大现金 dp[i][0] max(dp[i - 1][0], -price[i]); dp[i - 1][1] dp[i - 1][0] price[i] dp[i][1] max(dp[i - 1][0], dp[i - 1] pric…

【数据挖掘】PCA/LDA/ICA:A成分分析算法比较

一、说明 在深入研究和比较算法之前&#xff0c;让我们独立回顾一下它们。请注意&#xff0c;本文的目的不是深入解释每种算法&#xff0c;而是比较它们的目标和结果。 如果您想了解更多关于PCA和ZCA之间的区别&#xff0c;请查看我之前基于numpy的帖子&#xff1a; PCA 美白与…

Leetcode-每日一题【114.二叉树展开为链表】

题目 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终为 null 。 展开后的单链表应该与二叉树 先序遍历 顺序相同。 示例…

JavaEE——Spring中存取Bean的注解

目录 一、存储Bean对象 1、定义 2、存储方式 &#xff08;1&#xff09;、类注解 【1】、Controller&#xff08;控制器存储&#xff09; 【2】、Service&#xff08;服务存储&#xff09; 【3】、Repository&#xff08;仓库存储&#xff09; 【4】、Component&#xf…

9个可用于图片转文本的最佳免费 OCR 软件

光学字符识别 (OCR) 软件可帮助将不可编辑的文档格式&#xff08;例如 PDF、图像或纸质文档&#xff09;转换为可编辑和可搜索的机器可读格式。 OCR 应用程序通常用于从 PDF 和图像中捕获文本&#xff0c;并将文本转换为可编辑格式&#xff0c;例如 Word、Excel 或纯文本文件。…

Unity小游戏——武士打怪兽(总)

Unity小游戏——武士击杀小怪兽&#xff08;无限滚动的背景&#xff09;_七七喝椰奶的博客-CSDN博客 Unity小游戏——无限滚动的背景的改良_七七喝椰奶的博客-CSDN博客 Unity小游戏——怪物出现模式的管理_七七喝椰奶的博客-CSDN博客 Unity小游戏——武士和怪物的碰撞检测_七…

uniapp页面通信学习笔记

1、利用url传参进行通讯 A页面向B页面传递参数 uni.navigateTo({ url: test/test?id1&url encodeURIComponent(https://dcloud.io) }); B页面接收A页面传递的参数 export default { onLoad: function (option) { //option为object类型&#xff0c;会序列化上个页面…

将Windows的文件打包为Linux、Ubuntu可打开的格式

设置共享文件夹具体操作 设置共享文件夹 上述这篇文章完整讲述了如何设置一个可以在Windows及虚拟机之间互传文件的文件夹 7zip下载地址 Download 打包具体操作 a. 安装7-ZIP以后&#xff0c;直接在你想要打包的文件上点右键菜单&#xff0c;会有一个7-ZIP的子菜单栏&#…

STM32 HEX文件和BIN文件格式区别keil中的配置与生成

一、区别 HEX 文件: 是包括地址信息的,在烧写或下载HEX文件的时候,一般都不需要用户指定地址,因为HEX文件内部的信息已经包括了地址。HEX文件是用ASCII来表示二进制的数值。例如一般8-BIT的二进制数值0x3F,用ASCII来表示就需要分别表示字符3和字符F,每个字符需要一个BYTE…

【LeetCode每日一题】——946.验证栈序列

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 栈 二【题目难度】 中等 三【题目编号】 946.验证栈序列 四【题目描述】 给定 pushed 和 p…

C++OpenCV(6):图像阈值操作

&#x1f506; 文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 &#x1f506; OpenCV项目地址及源代码&#xff1a;点击这里 文章目录 图像阈值化 图像阈值化 阈值又叫临界值&#xff0c;是指一个效应能够产生的最低值或最高值。 例如我们选择的阈值为125&#xff0c;则…

[SQL挖掘机] - union/union all 使用注意事项

因为当使用union和union all操作符时&#xff0c;有一些注意事项需要考虑&#xff1a; 1. 列数和数据类型匹配&#xff1a; 要使用union或union all合并结果集&#xff0c;两个或多个查询的 select 语句必须返回相同数量和类型的列。确保每个查询返回相同的列数&#xff0c;并…

WPF实战学习笔记12-创建备忘录接口

创建备忘录接口 添加文件 新建文件 MyToDo.Api ./Controllers/MemoController.cs ./Service/IMemoService.cs ./Service/MemoService.cs MyToDo.Share ./Parameters/QueryParameter.cs QueryParameter.cs 查询参数类 using System; using System.Collections.Generic…

智能网关实现混凝土搅拌机无人自动化

“以前的搅拌站生产时&#xff0c;是需要人工巡检的&#xff0c;运送物料和搅拌时产生的大量粉尘污染和噪音&#xff0c;让工人苦不堪言。但是如果有了物联网搅拌站监测系统智慧园区项目落地后&#xff0c;工人也不用去现场忍受噪音和粉尘了。” 行业痛点 传统模式下的混泥土…

机器学习实战11-基于K-means算法的文本聚类分析,生成文本聚类后的文件

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍机器学习实战11-基于K-means算法的文本聚类分析&#xff0c;生成文本聚类后的文件。文本聚类分析是NLP领域的一个核心任务&#xff0c;通过将相似的文本样本分组&#xff0c;可以帮助我们发现隐藏在文本数据中的模式和结…

力扣题库刷题笔记73--矩阵置零

1、题目如下&#xff1a; 2、个人Python代码实现 3、个人Python代码思路 a、声明2个空数组p、q&#xff0c;用于存放值为0的元素matrix[i][j]的下标 b、首先遍历二维数组matrix&#xff0c;找到值为0的元素matrix[i][j]&#xff0c;将下标i加入数组p&#xff0c;将下标j加入数…

在Android中使用新版proguard混淆器的方式

文章目录 一、Proguard混淆器二、新版混淆器使用方式(插件版)三、R8与proguard四、参考链接 一、Proguard混淆器 Proguard是Android开发时经常会用到的一个混淆工具&#xff0c;在Android SDK中已经集成了一个免费的Proguard版本&#xff0c;位于/tools/proguard目录中。对于A…