《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. ...
随机推荐
- Postman(调试工具)
Postman Postman用法简介-Http请求模拟工具 时间 2015-09-26 23:52:00 博客园-原创精华区 原文 http://www.cnblogs.com/codingbl ...
- 12、多空格&多制表符文本之cut域分割终极方案
解决方法分为如下三步: (1) 使用“tr”命令将制表符转换为空格: (2) 使用“tr”命令将多个重复空格删除,保留一个空格: (3) 使用“cut”命令进 ...
- C#使用Json.NET解析Json
本文转载自 http://xiaosheng.me/2016/10/01/article25/ 最近在 C# 项目中需要使用到 Json 格式的数据,我简单上网搜索了一下,基本上有两种操作 Json ...
- mysql失效的几种情况
1.如果查询条件中有or,即使查询的条件中带有索引也会失效,如果想使用or,又不想让索引失效,只能将or条件中的所有列都加上索引 2.like 查询一%开头用不上索引, 3.隐式转换会使索引失效 比如 ...
- haml
创建: 2019/05/23 文档: http://haml.info/docs/yardoc/file.REFERENCE.html 安装 安装 gem "haml" ...
- Mybatis中文模糊查询,数据库中有数据,但无结果匹配
1.Mybatis中文模糊查询,数据库中有数据,但无结果匹配 1.1 问题描述: Mybatis采用中文关键字进行模糊查询,sql语句配置无误,数据库有该数据,且无任何报错信息,但无查询结果 1.2 ...
- java解析xml实例——获取天气信息
获取xml并解析其中的数据: package getweather.xml; import java.io.IOException; import java.util.HashMap; import ...
- 洛谷P3068 [USACO13JAN]派对邀请函Party Invitations
P3068 [USACO13JAN]派对邀请函Party Invitations 题目描述 Farmer John is throwing a party and wants to invite so ...
- 洛谷P1065 作业调度方案
P1065 作业调度方案 题目描述 我们现在要利用m台机器加工n个工件,每个工件都有m道工序,每道工序都在不同的指定的机器上完成.每个工件的每道工序都有指定的加工时间. 每个工件的每个工序称为一个操作 ...
- docker默认存储空间用完情况下,做迁移数据
由于docker默认存放数据路径为/var/lib/docker,但运行了一段时间后,发现/var/lib/docker下的目录文件过大,导致此分区空间不够用.通过以下方法,解决该问题. 如何避免: ...