《Head First 设计模式》之观察者模式——天气显示
观察者模式(Observer)
——在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。
(出版者Subject+订阅者Observer=观察者模式)
- 特点:定义并维护对象之间的一对多关系
- 原则:为交互对象之间的松耦合设计而努力
- 示例(气象站类图)

三个接口:
public interface Subject{
public void registerObserver(Observer o);//注册观察者
public void removeOberver(Observer o);//删除观察者
public void notifyObserver();//通知观察者
}
public interface Observer{
public void update(float temp, float humidity, float pressure);
}
public interface DisplayElement{
public void display();
}
在WeatherData中实现主题接口:
public class WeatherData implements Subject{
private ArrayList observers;//记录观察者
private float temperature;
private float humidity;
private float pressure;
public WeatherData(){
observers = new ArrayList();
}
public void registerObserver(Observer o){//注册观察者
observers.add(o);
}
public void removeOberver(Observer o){//删除观察者
int i = observers.indexOf(o);
if(i >= 0){
observers.remove(0);
}
}
public void notifyObservers(){
for(int i = 0; i < observers.size(); i++){ //通知每一个观察者
Observer observer = (Observer)observers.get(i);
observer.update(temperature, humidity, pressure);
}
}
public void measurementsChanged(){
notifyObservers();
}
public void setMeasurements(float temp, float hum, float pre){
this.temperature = temp;
this.humidity = hum;
this.pressure = pre;
measurementsChanged();
}
}
实现CurrentConditionDisplay.java
public class CurrentConditionsDisplay implements Observer, DisplayElement{
private float temperature;
private float humidity;
private Subject weatherData;
public CurrentConditionsDisplay(Subject weatherData){//构造器需要weatherData对象作为注册之用
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
public void update(float temp, float humidity, float pressure){
this.temperature = temp;
this.humidity = humidity;
display();
}
public void display(){
//输出
}
}
测试程序:
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();//建立weatherData对象
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);//将对象传给三个Observer,即add观察者
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 90, 29.2f);
}
}
Java内置的观察者模式
上述示例实现信息由Subject “推送(push)” 至Observer,使用Java内置的观察者模式可以使用推(push)或拉(pull)的方式传送数据。不同的是WeatherData现在扩展自Observable类,并继承到一些add、delete、notify观察者的方法。
Subject -> java.util.Observable(类)
Observer -> java.util.Observer(接口)

Observable如何送出通知?
首先需要利用扩展 java.util.Observable 接口产生“可观察者”类(想要进行通知,则必须调用Observable类的setChanged方法,但是Observable的setChanged方法为protected,故只能使用继承来实现自己的主题对象),然后:
- 调用setChanged(),标记状态已经改变的事实;
- 调用notifyObservers()中的一个:notifyObservers() 或 notifyObservers(Object arg)
Observer如何接收通知?
update(Observable o, Object arg) :主题Observable作为第一变量,好让观察者知道是哪个主题通知它的。Object arg正是传入notifyObservers(Object arg)的数据对象,如果没有说明则为空。
若想push数据给观察者,可以把数据作数据对象传送给notifyObservers(Object arg)方法。否则,观察者就必须从可观察者对象中pull数据。如何拉数据?
WeatherData.java
public class WeatherData extends Observable{
private float temperature;
private float humidity;
private float pressure;
public WeatherData(){ } //无需建立观察者列表ArrayList了
public void measurementsChanged(){
setChanged();//状态已经改变
notifyObservers();//pull
}
public void setMeasurements(float temp, float hum, float pre){
this.temperature = temp;
this.humidity = hum;
this.pressure = pre;
measurementsChanged();
}
public float getTemperature(){
return temperature;
}
public float gethumidity(){
return humidity;
}
public float getpressure(){
return pressure;
}
}
CurrentConditionDisplay.java
public class CurrentConditionsDisplay implements Observer, DisplayElement{
private float temperature;
private float humidity;
Observable observable;
public CurrentConditionsDisplay(Observable observable){
this.observable = observable;
observable.addObserver(this);
}
public void update(Observable o, Object arg){
if(o instanceof WeatherData){
WeatherData weatherData = (WeatherData)o;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.gethumidity();
display();
}
}
public void display(){
//输出
}
}
notice:
- 不想推送的时候,不调用setChanged()方法即可
- 通知顺序不依赖于注册的顺序(即主题通知观察者的顺序与添加观察者的顺序无关)
- setChanged()方法的必要性:若无,则温度计读数每十分之一度就会更新,造成WeatherData对象持续不断地通知观察者。若希望温差达到半度时更新,就调用setChanged()。有更多的弹性,更适当地通知观察者。
使用Java自带的观察者模式的缺点:
- Observable是一个类,而不是一个接口,导致Observable类的扩展性不高,不如自己实现的观察者模式灵活
- Observable将某些方法保护了起来(setChanged()和clearChanged()为protected),这意味着除非继承自Observable,否则将有关键的方法不能调用。导致无法通过组合的方式使其它类获得Observable类的功能。违反了设计原则“多用组合,少用继承”。
《Head First 设计模式》之观察者模式——天气显示的更多相关文章
- [JS设计模式]:观察者模式(即发布-订阅者模式)(4)
简介 观察者模式又叫发布---订阅模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知. 举一个现实生活中的例子,例如小 ...
- 乐在其中设计模式(C#) - 观察者模式(Observer Pattern)
原文:乐在其中设计模式(C#) - 观察者模式(Observer Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 观察者模式(Observer Pattern) 作者:weba ...
- 设计模式之观察者模式(Observable与Observer)
设计模式之观察者模式(Observable与Observer) 好久没有写博客啦,之前看完了<设计模式之禅>也没有总结一下,现在回忆一下设计模式之观察者模式. 1.什么是观察者模式 简单情 ...
- 8.5 GOF设计模式四: 观察者模式Observer
GOF设计模式四: 观察者模式Observer 现实中遇到的问题 当有许多不同的客户都对同一数据源感兴趣,对相同的数据有不同的处理方式,该如 何解决?5.1 定义: 观察者模式 观察者模式 ...
- php 设计模式之观察者模式(订阅者模式)
php 设计模式之观察者模式 实例 没用设计模式的代码,这样的代码要是把最上面那部分也要符合要求加进来,就要修改代码,不符合宁增不改的原则 介绍 观察者模式定义对象的一对多依赖,这样一来,当一个对象改 ...
- 实践GoF的23种设计模式:观察者模式
摘要:当你需要监听某个状态的变更,且在状态变更时通知到监听者,用观察者模式吧. 本文分享自华为云社区<[Go实现]实践GoF的23种设计模式:观察者模式>,作者: 元闰子 . 简介 现在有 ...
- java_设计模式_观察者模式_Observer Pattern(2016-07-27)
看了好几篇文章,最终还是觉得<Head First 设计模式>举得例子比较符合观察者模式. 观察者模式概述: 观察者模式有时被称作发布/订阅模式,它定义了一种一对多的依赖关系,让多个观察者 ...
- Head First 设计模式之观察者模式(Observer Pattern)
前言: 这一节开始学习观察者模式,开始讲之前会先像第一节那样通过一个应用场景来引入该模式.具体场景为:气象站提供了一个WeatherData对象,该对象可以追踪获取天气的温度.气压.湿度信息,Weat ...
- 设计模式学习——观察者模式(Observer Pattern)
0. 前言 观察者模式在许多地方都能够用到,特别是作为MVC模式的一部分,在MVC中,模型(M):存放数据,视图(V):显示数据.当模型中的数据发生改变时,视图会得到通知,这是典型的观察者模式. 1. ...
随机推荐
- 机器学习前沿热点——Deep Learning
深度学习是机器学习研究中的一个新的领域,其动机在于建立.模拟人脑进行分析学习的神经网络,它模仿人脑的机制来解释数据,例如图像.声音和文本.深度学习是无监督学习的一种. 深度学习的概念源于人工神经网络的 ...
- CentOS 7 安装 Zabbix 3.0
CentOS7搭建Zabbix 一.安装数据库: 1. 安装数据库:sudo yum grouinstall mariadb –y 2. 启动数据库:sudo systemctl start ...
- Intent的简单概述
Intent是负责在系统组件之间传递信息的一个对象,就像名字一样,是一个意图,可以将当前组件的意图传递给系统,例如启动Activity等,还可以在传递的时候附加上一些值,可以用Bundle对象封装这些 ...
- Jmeter进行简单mysql数据库测试
1.环境准备: mysql: mysql-5.7.17.msi jdbc驱动: 自己百度一下即可 Jmeter: 3.2 2.打开Jmeter,创建测试计划, 点击浏览,添加jdbc驱动 3.添 ...
- xgene:疾病相关基因,耳聋,彩色,老年痴呆,帕金森
神经元的传递:一个下游神经元,它接受其上游神经元的各个突触传过来的信号,然而,每个突触对该下游神经元的激活权重是不同的. 从神经网络的本质上说,当人连续.多次遭受失败的时候,大脑内就会释放大量的抑制性 ...
- 【Redis】Redis事务详解,Redis事务支持回滚(不支持悲观锁)
1.redis事物参考:https://baijiahao.baidu.com/s?id=1613631210471699441&wfr=spider&for=pc (php操作red ...
- Multi-task Pose-Invariant Face Recognition 论文笔记
摘要: 在不受限制的环境中拍摄的人脸图像通常包含显著的姿态变化,这会显著降低设计用于识别正面的算法的性能.本文提出了一种新颖的面部识别框架,能够处理±90°偏航范围内的全方位姿势变化.所提出的框架首先 ...
- redis系列:主从复制
1 简介 这篇文章主要讲述Redis的主从复制功能.会依次从环境搭建.功能测试和原理分析几个方面进行介绍. 2 准备工作 服务器架构图如下 启动主服务器101,使用info replication命令 ...
- const指针与指向const的指针
当使用带有const的指针时其实有两种意思.一种指的是你不能修改指针本身的内容,另一种指的是你不能修改指针指向的内容.听起来有点混淆一会放个例子上来就明白了. 先说指向const的指针,它 ...
- Spring基本原理模拟(IoC部分)
package ioc; import java.io.File; import java.lang.reflect.Method; import java.util.Collections; imp ...