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

article/2025/9/10 16:27:51

定义

观察者(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://chatgpt.dhexx.cn/article/UgLJPEoD.shtml

相关文章

大聪明教你学Java设计模式 | 第十三篇:观察者模式

前言 &#x1f34a;作者简介&#xff1a; 不肯过江东丶&#xff0c;一个来自二线城市的程序员&#xff0c;致力于用“猥琐”办法解决繁琐问题&#xff0c;让复杂的问题变得通俗易懂。 &#x1f34a;支持作者&#xff1a; 点赞&#x1f44d;、关注&#x1f496;、留言&#x1f4…

Java 设计模式(十三):代理模式

参考链接&#xff1a;代理模式-Proxy Pattern 近年来&#xff0c;代购已逐步成为电子商务的一个重要分支。代购简单来说就是找人帮忙购买所需要的商品&#xff0c;代购网站就是其中一种产物&#xff0c;它为消费者提供在线的代购服务&#xff0c;如果看中某国外购物网站上的商…

Java设计模式:观察者模式

一、什么是观察者模式&#xff1f; 又叫做发布-订阅模式&#xff0c;定义对象间一种一对多的依赖关系&#xff0c;使得每当一个对象改变状态&#xff0c;则所有依赖于它的对象都会得到通知并自动更新。UML结构图如下&#xff1a; 其中涉及到四种角色&#xff1a; 1.抽象目标&a…

初探Java设计模式------观察者模式

前言 最近刚开始学习RxJava&#xff0c;众所周知&#xff0c;Rxjava就是扩展的观察者模式&#xff0c;所以想学习Rxjava&#xff0c;先入手了解一下观察者模式是很有必要的。那么今天就先稍微了解一下什么是观察者模式。 定义 观察者(Observer)模式&#xff1a;是对象的行为模…

java设计模式(3)--观察者模式

&#xff08;一&#xff09;观察者模式 观察者模式定义对象间的一种一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知并被自动更新。 该模式有以下角色&#xff1a; &#xff08;1&#xff09;抽象主题&#xff08;Subjec…

Java设计模式之行为型:观察者模式

一、什么是观察者模式&#xff1a; 观察者模式又称为 发布-订阅模式&#xff0c;定义了对象之间一对多依赖关系&#xff0c;当目标对象(被观察者)的状态发生改变时&#xff0c;它的所有依赖者(观察者)都会收到通知。一个观察目标可以对应多个观察者&#xff0c;而这些观察者之间…

java监听设计模式(java观察者设计模式)

今天给大家分享一下观察者设计模式&#xff08;监听设计模式&#xff09;&#xff0c;该模式在很多主流得框架、源码中使用率非常高。在分享之前先给大家讲一个我们使用手机的一个场景&#xff0c;我们都用过手机&#xff0c;当我们手机来电话的时候&#xff0c;会有各种复杂的…

【十一】设计模式~~~结构型模式~~~代理模式(Java)

【学习难度&#xff1a;★★★☆☆&#xff0c;使用频率&#xff1a;★★★★☆】 6.1. 模式动机 在某些情况下&#xff0c;一个客户不想或者不能直接引用一个对 象&#xff0c;此时可以通过一个称之为“代理”的第三者来实现 间接引用。代理对象可以在客户端和目标对象之间起…

JAVA架构之路(设计模式之观察者模式)

设计模式之观察者模式 定义&#xff1a;对象间的一种一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知并被自动更新 核心原理&#xff1a; 1.被观察者中维护一个观察者对象列表 2.观察者可新增可可移除。 需要角色&#…

程序员百宝箱---搭建自己专属的在线工具集

相信各位开发者/程序员在开发过程中都使用过各种在线工具吧。比如 1 校验或格式化 json 字符串 2 使用 base64 的加密解密&#xff0c;url 的编码解码 urlencode、urldecode 等 3 调试正则表达式是否正确 4 时间戳与格式化日期互相转换 5 文本对比&#xff0c;比较两个代码文件…

如何部署JSP应用到阿里云服务器上(一)

今天讲解一下如何部署JSP应用到阿里云服务器上&#xff0c;我使用的后台服务器是 Tomcat服务器&#xff0c;服务器应用的开发语言是 Java Web &#xff0c;后台的数据库使用的是MySQL 1 打开阿里云官方网站 https://www.aliyun.com/?utm_mediumtext&utm_sourcebdbrand&am…

开源项目精选推荐-杨小杰工具箱(YoungxjTools)

演示 预览地址: https://tools.yum6.cn/ 程序介绍 01、首页底部友情链接 02、网站公告页面功能 03、内置留言管理功能 04、后台网站信息设置 05、内置smtp发信配置 06、支持两主题的切换 07、关于页面支持留言, 08、程序已集成32种小工具 更多功能 介绍 请搭建 自行测试

C++构造函数之初始化列表

C构造函数之初始化列表 构造函数可以说是对于C每个类来说最重要的组成部分&#xff0c;之前也详细介绍过构造函数的相关知识&#xff0c;今天给构造函数进行补充&#xff0c;主要说明一下构造函数的初始值列表 一、初始化列表的写法 仍然以之前介绍构造函数时使用的学生类来…

C++初始化列表详解

目录&#xff1a; 定义 使用初始化列表的原因 必须使用初始化列表的时候 成员变量的顺序 定义 与其他函数不同&#xff0c;构造函数除了有名字&#xff0c;参数列表和函数体之外&#xff0c;还可以有初始化列表&#xff0c;初始化列表以冒号…

C++类的初始化列表

意义 初始化列表是类中构造函数的一部分&#xff0c;用于实例化类中变量时 赋初值。 需要先了解 构造函数的基本知识。CSDN-构造函数https://blog.csdn.net/weixin_44212838/article/details/124901019?spm1001.2014.3001.5501 用法 在函数头与函数体之间&#xff0c;用一…

详解初始化列表

初始化列表 定义 构造函数有个特殊的初始化方式叫“初始化表达式表”&#xff08;简称初始化列表&#xff09;。初始化列表位于函数参数表之后&#xff0c;却在函数体 {} 之前。这说明该表里的初始化工作发生在函数体内的任何代码被执行之前。 Date(int year, int month, in…

C++ 成员初始化列表

这里写目录标题 数据成员是某一个类的对象&#xff0c;且这个类没有默认构造函数数据成员的类型是const或者引用子类初始化父类初始化列表先后顺序使用成员初始化列表的优点 在以下三种情况下需要使用初始化成员列表&#xff1a; 需要初始化的数据成员是某一个类的对象&#xf…

【深入理解】初始化列表

目录 一、什么是初始化列表&#xff1f; 二、初始化列表长啥样&#xff1f; 三、初始化列表的特性 1、由于是在定义阶段进行的初始化&#xff0c;所以&#xff0c;只能在定义阶段进行的初始化类型便只能在初始化列表中进行初始化。 2、初始化顺序不是跟着初始化列表走的&#x…

C++ 初始化列表详解

目录 1.什么是初始化列表 2.什么时候需要使用初始化列表&#xff1f; 3.初始化列表的效率 4.初始化列表的初始化顺序 1.什么是初始化列表 class A { public:A(int value):m_dada(value){}private:int m_dada; }; 如上图&#xff0c;红色圈起来的部分&#xff0c;就是构造函…

【C++】-- 初始化列表

目录 一、用初始化列表初始化对象 1.初始化列表用法 2.初始化列表特性 二、explicit关键字 1.内置类型的隐式转换 2.如何避免单参构造函数初始化发生隐式类型转换 三、匿名对象 1.匿名对象定义 2.匿名对象应用场景 创建一个类对象时&#xff0c;编译器通过调用构造函…