定义

观察者(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废弃原因及解决方案

Java设计模式(2 / 23):观察者模式相关推荐

  1. java 观察者模式_重学 Java 设计模式:实战观察者模式「模拟类似小客车指标摇号过程,监听消息通知用户中签场景」...

    一.前言 知道的越多不知道的就越多 编程开发这条路上的知识是无穷无尽的,就像以前你敢说精通Java,到后来学到越来越多只想写了解Java,过了几年现在可能想说懂一点点Java.当视野和格局的扩大,会让 ...

  2. Java设计模式:23种设计模式全面解析,墙都不扶就服你

    命令模式:将命令请求封装为一个对象,使得可以用不同的请求来进行参数化. 迭代器模式:一种遍历访问聚合对象中各个元素的方法,不暴露该对象的内部结构. 观察者模式:对象间的一对多的依赖关系. 仲裁者模式: ...

  3. Java 设计模式之《观察者模式》

    很久之前,自己也曾看过一些设计模式的内容,最近在做一些程序代码设计的时,发现忘得差不多了,很多模式也只是有大致影响,决定重新将一些常用的模式复习一下.今天一个模式观察者模式. 观察者模式 观察者模式属 ...

  4. Java设计模式10:观察者模式

    观察者模式 观察者模式也叫作发布-订阅模式,也就是事件监听机制.观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态上发生变化时,会通知所有观察者对象,使他 ...

  5. Java设计模式19:观察者模式(Observer)

    观察者模式 意图 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于他的对象都得到通知并被自动更新 适用性 1.当一个抽象模型有两个方面,其中一个依赖另外一个 2.当对一个对象的 ...

  6. Java 设计模式情景分析——观察者模式

    观察者模式是一种使用频率非常高的模式,有时也被称作发布/订阅模式,属于行为型模式,它最常用的是 GUI 系统.发布/订阅系统,它一个重要作用就是解耦,使得它们之间的依赖性更小.观察者模式定义了对象间一 ...

  7. 学区摇号软件设计_重学 Java 设计模式:实战观察者模式「模拟类似小客车指标摇号过程,监听消息通知用户中签场景」...

    作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获!

  8. 重学 Java 设计模式:实战观察者模式「模拟类似小客车指标摇号过程,监听消息通知用户中签场景」

    作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获!

  9. java设计模式 观察者模式_理解java设计模式之观察者模式

    在生活实际中,我们经常会遇到关注一个事物数据变化的情况,例如生活中的温度记录仪,当温度变化时,我们观察它温度变化的曲线,温度记录日志等.对于这一类问题,很接近java设计模式里面的"观察者模 ...

  10. 【java设计模式】-00目录

    开篇 [java设计模式]-01设计模式简介 创建型模式: [java设计模式]-02工厂模式(Factory Pattern) [java设计模式]-03抽象工厂模式(Abstract Factor ...

最新文章

  1. 小型电商web架构!小而美!
  2. 网络设备Web登录检测工具device-phamer
  3. python tensorflow tf.session类
  4. Spring 基于 Java 的配置 - 如何不用Beans.xml照样描述bean之间的依赖关系
  5. 字符串替换方法的优劣
  6. 域账号更改密码之后代理需要重新配置
  7. 【更新】深度学习推荐系统
  8. 电商运营、美工必备导航类网站,有效提高工作效率
  9. mysql数据库字段字符转数字批量语句_MySQL数据库批量替换指定字段字符串SQL语句命令...
  10. [整理]CHttpConnection的使用
  11. hdu 1520 Anniversary party(第一道树形dp)
  12. mysql 主从库_MySQL数据库之mysql 主库有数据通过锁库做主从
  13. 如何用python 巡检华为交换机?
  14. pythonic希腊典故_希腊神话习语(整理)
  15. 电脑Java安装 报错_Windows10系统电脑安装Java开发环境的方法
  16. 模式串匹配Aho–Corasic算法 python实现
  17. jasypt.jar 1.9.2下载,加密解密
  18. birt什么意思中文翻译_有含义的英文网名带中文翻译
  19. Altium Designer系列:问题之无法打开pcb文件
  20. audio标签的播放、暂停、重播、进度拖拽等操作

热门文章

  1. STM32移植UCGUI3.90笔记
  2. 16进制字符串转化为10进制数
  3. centos8 默认nginx路径_CentOS 8系统安装Nginx Web服务器及常见配置过程
  4. python高级玩法_python pandas to_excel 高级玩法
  5. mysql用binlog恢复数据_利用mysql的binlog恢复数据
  6. 用python画明星_用python画一只可爱的皮卡丘实例
  7. 设计模式(二)设计模式的本质
  8. 数据结构 - 线索化二叉树(线索化与遍历)
  9. REVERSE-PRACTICE-BUUCTF-10
  10. docker安装与学习