Java设计模式(2 / 23):观察者模式

定义

观察者(Observer)模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
在这里插入图片描述

OO设计原则:为了交互对象之间的松耦合设计而努力。

案例:气象监测应用

概括

此系统中的三个部分是

  1. 气象站(获取实际气象数据的物理装置)
  2. WeatherData对象(追踪来自气象站的数据,并更新布告板)
  3. 布告板(显示目前天气状况给用户看)

WeatherData对象知道如何跟物理气象站联系,以取得更新的数据。

WeatherData对象会随即更新三个布告板的显示:

  1. 目前状况(温度、湿度、气压)、
  2. 气象统计
  3. 天气预报。

目标是建立一个应用,利用WeatherData对象取得数据,并更新三个布告板:目前状况、气象统计和天气预报 。

在这里插入图片描述

设计图

在这里插入图片描述

放码过来

气象站主程序

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);System.out.println("---");weatherData.setMeasurements(82, 70, 29.2f);System.out.println("---");weatherData.setMeasurements(78, 90, 29.2f);System.out.println("---Remove Observer---");weatherData.removeObserver(forecastDisplay);weatherData.setMeasurements(62, 90, 28.1f);}
}

布告板

打印展现接口

public interface DisplayElement {public void display();
}

主题

public interface Subject {public void registerObserver(Observer o);public void removeObserver(Observer o);public void notifyObservers();
}
实现主题接口的气象数据
import java.util.*;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;}}

观察者

public interface Observer {public void update(float temp, float humidity, float pressure);
}
实现观察者接口的目前状况布告板
public class CurrentConditionsDisplay implements Observer, DisplayElement {private float temperature;private float humidity;private WeatherData weatherData;public CurrentConditionsDisplay(WeatherData weatherData) {this.weatherData = weatherData;weatherData.registerObserver(this);}public void update(float temperature, float humidity, float pressure) {this.temperature = temperature;this.humidity = humidity;display();}public void display() {System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");}
}
实现观察者接口的气象统计布告板
public class StatisticsDisplay implements Observer, DisplayElement {private float maxTemp = 0.0f;private float minTemp = 200;private float tempSum= 0.0f;private int numReadings;private WeatherData weatherData;public StatisticsDisplay(WeatherData weatherData) {this.weatherData = weatherData;weatherData.registerObserver(this);}public void update(float temp, float humidity, float pressure) {tempSum += temp;numReadings++;if (temp > maxTemp) {maxTemp = temp;}if (temp < minTemp) {minTemp = temp;}display();}public void display() {System.out.println("Avg/Max/Min temperature = " + (tempSum / numReadings)+ "/" + maxTemp + "/" + minTemp);}
}
实现观察者接口的天气预报布告板
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");}}
}

运行结果

气象站主程序运行结果:

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
---Remove Observer---
Current conditions: 62.0F degrees and 90.0% humidity
Avg/Max/Min temperature = 75.5/82.0/62.0

现成轮子

Java API有内置的观察者模式。java.util包内包含最基本的Observer接口与Observable类,这和案例的Subject接口与Observer接口很相似。

Observer接口与Observable类使用上更方便,因为许多功能都已经事先准备好了。

package java.util;@Deprecated(since="9")
public interface Observer {void update(Observable o, Object arg);
}
package java.util;@Deprecated(since="9")
public class Observable {private boolean changed = false;private Vector<Observer> obs;public Observable() {obs = new Vector<>();}public synchronized void addObserver(Observer o) {if (o == null)throw new NullPointerException();if (!obs.contains(o)) {obs.addElement(o);}}public synchronized void deleteObserver(Observer o) {obs.removeElement(o);}public void notifyObservers() {notifyObservers(null);}public void notifyObservers(Object arg) {/** a temporary array buffer, used as a snapshot of the state of* current Observers.*/Object[] arrLocal;synchronized (this) {/* We don't want the Observer doing callbacks into* arbitrary code while holding its own Monitor.* The code where we extract each Observable from* the Vector and store the state of the Observer* needs synchronization, but notifying observers* does not (should not).  The worst result of any* potential race-condition here is that:* 1) a newly-added Observer will miss a*   notification in progress* 2) a recently unregistered Observer will be*   wrongly notified when it doesn't care*/if (!changed)return;arrLocal = obs.toArray();clearChanged();}for (int i = arrLocal.length-1; i>=0; i--)((Observer)arrLocal[i]).update(this, arg);}public synchronized void deleteObservers() {obs.removeAllElements();}protected synchronized void setChanged() {changed = true;}protected synchronized void clearChanged() {changed = false;}public synchronized boolean hasChanged() {return changed;}public synchronized int countObservers() {return obs.size();}
}

注意:Observer和Observable在Java 9标记为废弃。

Deprecated. This class and the Observer interface have been deprecated. The event model supported by Observer and Observable is quite limited, the order of notifications delivered by Observable is unspecified, and state changes are not in one-for-one correspondence with notifications. For a richer event model, consider using the java.beans package. For reliable and ordered messaging among threads, consider using one of the concurrent data structures in the java.util.concurrent package. For reactive streams style programming, see the java.util.concurrent.Flow API.

Link

参考资料

  1. 《Head First 设计模式》
  2. Observable (Java SE 9 & JDK 9 )
  3. Java 9:Observer和Observable废弃原因及解决方案

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

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

相关文章

二叉树概述

各种实现和应用以后放链接 一、二叉树的基本概念 二叉树&#xff1a;二叉树是每个节点最多有两个子树的树结构。 根节点&#xff1a;一棵树最上面的节点称为根节点。 父节点、子节点&#xff1a;如果一个节点下面连接多个节点&#xff0c;那么该节点称为父节点&#xff0c;它…

Java设计模式(1 / 23):策略模式

定义 策略&#xff08;Strategy&#xff09;模式定义了算法族&#xff0c;分别封装起来&#xff0c;让它们之间可以互相替换 &#xff0c;此模式让算法的变化独立于使用算法的客户。 案例&#xff1a;模拟鸭子应用 一开始 新需求&#xff1a;模拟程序需要会飞的鸭子 在父类新…

Java设计模式(3 / 23):装饰者模式

文章目录定义案例1&#xff1a;三点几啦首次尝试再次尝试设计原则&#xff1a;类应该对扩展开放&#xff0c;对修改关闭尝用装饰者模式装饰者模式特征本例的类图放码过来饮料类HouseBlendDarkRoastEspressoDecaf调料装饰类MilkMochaSoyWhip运行测试类案例2&#xff1a;编写自己…

c语言知识体系

原文&#xff1a;https://blog.csdn.net/lf_2016/article/details/80126296#comments

《游戏编程入门 4th》笔记(1 / 14):Windows初步

文章目录Windows编程概述获取Windows理解Windows消息机制多任务多线程事件处理DirectX快速概览Direct3D是什么Window程序基础创建第一个Win32项目理解WinMainWinMain函数调用完整的WinMainGetMessage函数调用寻求帮助Windows编程概述 DirectX&#xff0c;流行的游戏编程库。它…

17校招真题题集(1)1-5

注&#xff1a;本系列题目全是按照通过率降序来排列的&#xff0c;基本保证题目难度递增。 1、 题目名称&#xff1a;游戏任务标记 来源&#xff1a;腾讯 题目描述 游戏里面有很多各式各样的任务&#xff0c;其中有一种任务玩家只能做一次&#xff0c;这类任务一共有1024个…

《游戏编程入门 4th》笔记(2 / 14):监听Windows消息

文章目录编写一个Windows程序理解InitInstanceInitInstance函数调用InitInstance的结构理解MyRegisterClassMyRegisterClass函数调用MyRegisterClass的作用揭露WinProc的秘密WinProc函数调用WinProc的大秘密什么是游戏循环The Old WinMain对持续性的需要实时终止器WinMain和循环…

17校招真题题集(2)6-10

注&#xff1a;本系列题目全是按照通过率降序来排列的&#xff0c;基本保证题目难度递增。 6、 题目名称&#xff1a;Fibonacci数列 来源&#xff1a;网易 题目描述 Fibonacci数列是这样定义的&#xff1a; F[0] 0 F[1] 1 for each i ≥ 2: F[i] F[i-1] F[i-2] 因此&am…

QT5的数据库

#include <QtSql> QT sql QSqlDatabase类实现了数据库连接的操作 QSqlQuery类执行SQL语句 QSqlRecord类封装数据库所有记录 QSqlDatabase类 [cpp] view plaincopy print?QSqlDatabase db QSqlDatabase::addDatabase("QOCI"); db.setHostName("localh…

数据结构课上笔记6

本节课介绍了单链表的操作实现细节&#xff0c;介绍了静态链表。 链表带头的作用&#xff1a;对链表进行操作时&#xff0c;可以对空表、非空表的情况以及 对首元结点进行统一处理&#xff0c;编程更方便。 下面给出带头的单链表实现思路&#xff1a; 按下标查找&#xff1a; …

《Unity2018入门与实战》笔记(9 / 9):个人总结

个人总结 脚本语言学习的窍门 尽可能多读、多写、多说脚本语言&#xff01; Link 游戏制作步骤 设计游戏时一般会遵循5个步骤&#xff1a; 罗列出画面上所有的对象。确定游戏对象运行需要哪些控制器脚本。确定自动生成游戏对象需要哪些生成器脚本。准备好用于更新UI的调度…

17校招真题题集(3)11-15

注&#xff1a;本系列题目全是按照通过率降序来排列的&#xff0c;基本保证题目难度递增。 11、 题目名称&#xff1a;买苹果 来源&#xff1a;网易 题目描述 小易去附近的商店买苹果&#xff0c;奸诈的商贩使用了捆绑交易&#xff0c;只提供6个每袋和8个每袋的包装(包装不…

Qt学习:QDomDocument

QDomDocument类代表了一个XML文件 QDomDocument类代表整个的XML文件。概念上讲&#xff1a;它是文档树的根节点&#xff0c;并提供了文档数据的基本访问方法。由于元素、文本节点、注释、指令执行等等不可能脱离一个文档的上下文&#xff0c;所以文档类也包含了需要用来创建这些…

《事实:用数据思考,避免情绪化决策》笔记

文章目录一分为二负面思维直线思维恐惧本能规模错觉以偏概全命中注定单一视角归咎他人情急生乱一分为二 要做到实事求是&#xff0c; 就要做到当你听到一分为二的说法时&#xff0c; 你就能迅速认识到这种说法描述的是一种两极分化的图画&#xff0c; 而两极之间存在一道巨大的…

顺序存储线性表实现

在计算机中用一组地址连续的存储单元依次存储线性表的各个数据元素,称作线性表的顺序存储结构。 顺序存储结构的主要优点是节省存储空间&#xff0c;因为分配给数据的存储单元全用存放结点的数据&#xff08;不考虑c/c语言中数组需指定大小的情况&#xff09;&#xff0c;结点之…

QT5生成.exe文件时,出现缺少QT5core.dll文件解决方法

在 http://qt-project.org/downloads 下载Qt SDK安装需要Qt版本。在QtCreator下&#xff0c;程序可以正常运行&#xff0c;但是当关闭QtCreator后&#xff0c;在DeBug目录下再运行相应的*.exe程序时&#xff0c;会提示缺少Qt5Core.dll错误。解决方法&#xff1a;添加电脑环境变…

《基于Java实现的遗传算法》笔记(7 / 7):个人总结

文章目录为何采用遗传算法哪些问题适合用遗传算法解决遗传算法基本术语一般遗传算法的过程基本遗传算法的伪代码为何采用遗传算法 遗传算法是机器学习的子集。在实践中&#xff0c;遗传算法通常不是用来解决单一的、特定问题的最好算法。对任何一个问题&#xff0c;几乎总有更…

单链表不带头标准c语言实现

链表是一种物理存储单元上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点&#xff08;链表中每一个元素称为结点&#xff09;组成&#xff0c;结点可以在运行时动态生成。每个结点包括两个部分&#xff1a;一个是…

Java设计模式(4 / 23):单例模式

文章目录单例模式的应用场景饿汉式单例模式懒汉式单例模式改进&#xff1a;synchronized改进&#xff1a;双重检查锁改进&#xff1a;静态内部类破坏单例用反射破坏单例用序列化破坏单例解密注册式单例模式枚举式单例模式解密容器式单例线程单例实现ThreadLocal单例模式小结参考…

约瑟夫环-(数组、循环链表、数学)

约瑟夫环&#xff08;约瑟夫问题&#xff09;是一个数学的应用问题&#xff1a;已知n个人&#xff08;以编号1&#xff0c;2&#xff0c;3...n分别表示&#xff09;围坐在一张圆桌周围。从编号为k的人开始报数&#xff0c;数到m的那个人出列&#xff1b;他的下一个人又从1开始报…