观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖着都会受到通知并且自动更新。

我们先看下类图:

首先我们自己创建Subject接口,定义了注册观察者,移除观察者和通知观察者三个函数。

 package headfirst.observer.weather;

 public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}

而WeatherData实现了这个接口,内部维护的是一个ArrayList的Observer。

 package headfirst.observer.weather;

 import java.util.*;

 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 removeObserver(Observer o) {
int i = observers.indexOf(o);
if (i >= 0) {
observers.remove(i);
}
} 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 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;
}
}

DisplayElement接口只包含了一个方法,也就是display()。但布告板需要显示时,调用此方法。

 package headfirst.observer.weather;

 public interface DisplayElement {
public void display();
}

Observer接口定义了update函数,当Subject的内容发生改变时,会调用update函数来通知观察者更新状态值。

 package headfirst.observer.weather;

 public interface Observer {
public void update(float temp, float humidity, float pressure);
}

观察者需要存储Subject的引用,通过这个引用来进行注册。

 package headfirst.observer.weather;

 public class CurrentConditionsDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
private Subject weatherData; //构造函数的参数为Subject
public CurrentConditionsDisplay(Subject weatherData) {
this.weatherData = weatherData;
//把自己注册给Subject
weatherData.registerObserver(this);
} //更新时调用相应的display函数
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");
}
}

其他两个差不多:

ForecastDisplay
 package headfirst.observer.weather;

 import java.util.*;

 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");
}
}
}

StatisticsDisplay

 package headfirst.observer.weather;

 import java.util.*;

 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);
}
}

HeadDisplay

 package headfirst.observer.weather;

 public class HeatIndexDisplay implements Observer, DisplayElement {
float heatIndex = 0.0f;
private WeatherData weatherData; public HeatIndexDisplay(WeatherData weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
} public void update(float t, float rh, float pressure) {
heatIndex = computeHeatIndex(t, rh);
display();
} private float computeHeatIndex(float t, float rh) {
float index = (float)((16.923 + (0.185212 * t) + (5.37941 * rh) - (0.100254 * t * rh)
+ (0.00941695 * (t * t)) + (0.00728898 * (rh * rh))
+ (0.000345372 * (t * t * rh)) - (0.000814971 * (t * rh * rh)) +
(0.0000102102 * (t * t * rh * rh)) - (0.000038646 * (t * t * t)) + (0.0000291583 *
(rh * rh * rh)) + (0.00000142721 * (t * t * t * rh)) +
(0.000000197483 * (t * rh * rh * rh)) - (0.0000000218429 * (t * t * t * rh * rh)) +
0.000000000843296 * (t * t * rh * rh * rh)) -
(0.0000000000481975 * (t * t * t * rh * rh * rh)));
return index;
} public void display() {
System.out.println("Heat index is " + heatIndex);
}
}

接下来就是main函数了。

 package headfirst.observer.weather;

 import java.util.*;

 public class WeatherStationHeatIndex {

     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);
HeatIndexDisplay heatIndexDisplay = new HeatIndexDisplay(weatherData); weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 90, 29.2f);
}
}

可以看到这里实现的Observer模式有两个要注意的地方

  1. “推”模式,Subject内容一有变化,就主动向Observer推送消息。它是通过在Subject中的notifyObservers中对每个Observer调用update来实现的。如果要实现“拉”模式,因为在Observer保存了Subject的引用,所以可以通过定时的方式,向Subject拉取数据。
  2. 可以看到update函数是依赖于具体实现的,可以看到参数是什么温度,湿度等等。这样的接口是无法面向所有的应用的。不过Java内置了观察者模式相关的接口,可以在下一篇看到相关的实现。

观察者模式(一)--《Head First DesignPattern》的更多相关文章

  1. 观察者模式(二)--《Head First DesignPattern》

    我们用Java中自带的观察者模式接口来重写前面的例子. 先看一下类图: 这里用到了一个setChanged函数,它用来标记状态已经改变的事实,好让notifyObservers()知道当它调用时就应该 ...

  2. 23种设计模式--观察者模式-Observer Pattern

    一.观察者模式的介绍      观察者模式从字面的意思上理解,肯定有两个对象一个是观察者,另外一个是被观察者,观察者模式就是当被观察者发生改变得时候发送通知给观察者,当然这个观察者可以是多个对象,在项 ...

  3. java设计模式之观察者模式(9)

    Java观察者模式的浅析 简单地说,观察者模式定义了一个一对多的依赖关系,让一个或多个观察者对象监察一个主题对象.这样一个主题对象在状态上的变化能够通知所有的依赖于此对象的那些观察者对象,使这些观察者 ...

  4. CSharp设计模式读书笔记(20):观察者模式(学习难度:★★★☆☆,使用频率:★★★★★)

    观察者模式(Observer Pattern):定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新.观察者模式的别名包括发布-订阅(Publish/ ...

  5. &lt;C++ 实现设计模式&gt; 观察者模式

    观察者模式,又称公布--订阅,mvc模式等. 通俗点讲,比方股票来说,非常多人关注一支股票,派一个人去观察股票的情况,一有变化(观察),就通知全部的预定这个消息的人. 而我们常见的mvc模式,v是指v ...

  6. 我的Java设计模式-观察者模式

    相信大家都有看过<喜洋洋与灰太狼>,说的是灰太狼和羊族的"斗争",而每次的结果都是灰太狼一飞冲天,伴随着一句"我还会回来的......".为灰太狼感 ...

  7. 23种设计模式之观察者模式(Observer Pattern)

    观察者模式(Observer Pattern):定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主体对象,这个主题对象在状态发生变化时,会通知所有观察者.当一个对象改变需要同时改变其他对象, ...

  8. 谈谈JS的观察者模式(自定义事件)

    呼呼...前不久参加了一个笔试,里面有一到JS编程题,当时看着题目就蒙圈...后来研究了一下,原来就是所谓的观察者模式.就记下来...^_^ 题目 [附加题] 请实现下面的自定义事件 Event 对象 ...

  9. ObserverPattern(观察者模式)

    import java.util.ArrayList; import java.util.List; /** * 观察者模式 * @author TMAC-J * 牵一发而动全身来形容观察者模式在合适 ...

随机推荐

  1. POJ 2886Who Gets the Most Candies?(线段树)

    POJ 2886 题目大意是说有n个人围成一圈,游戏的起点是k,每个人持有一个数字(非编号)num,每次当前的人退出圈,下一个人是他左边的第num个(也就是说下一个退出的是k+num, k可以为负数, ...

  2. Lotus 迁移到Exchange 2010 POC 之在Exchange 2007安装Transport Suite!

    我们登录到Exchange 2007服务器,下载Transport 组件,下载地址如下,我们由于安装在Exchange 服务器上,所以需要安装64位版本:

  3. linux中less命令使用

    less与cat和more的区别: cat命令功能用于显示整个文件的内容单独使用没有翻页功能因此经常和more命令搭配使用,cat命令还有就是将数个文件合并成一个文件的功能. more命令功能:让画面 ...

  4. 使用IBatisNet的网站,修改database.config无效的问题解决

    这周五去客户那更新了一个使用了IBatisNet的Web项目,备份了项目.数据库之后,替换更新的文件(含bin目录)却报数据库连接错. 因为是接手的一个维护项目,加上交接有点问题,所以遇到问题只能自己 ...

  5. ios和android一并学习的体会

    如果说为什么要同时学习这两种不同的移动平台,其实有一定的“闲”的因素在里面. 相对于ios,android我是早半年接触的.最开始学习的时候也就是j2ee学习的延续,通过看视频连带看书学了大概一个月的 ...

  6. vss使用详解

    下面已VSS6.0为主: 一:安装VSS6.0 安装过程中可能会提示 退出,禁止(abort)  重试(retry)  忽略,跳过(Ignore)  ,我们选 Ignore  跳过此项, 路径自己选择 ...

  7. InitializingBean和init-method

    [spring的InitializingBean的 afterPropertiesSet 方法 和 init-method配置的 区别联系] InitializingBean Spring的Initi ...

  8. 索引的实现:B+树

    [ http://blog.csdn.net/stormbjm/article/details/12033673 ]   见<数据库系统概念>P323.   [从B树.B+树.B*树谈到R ...

  9. 转载:js和as间的交互

    转载一: 提及AS3与外部脚本的交互,笔者认为可以总结成两种.一是AS3调用外部函数,二是外部脚本调用AS3函数.无外乎就 这两种.在调用函数的同时,我们还可以向函数传递一些参数.这就达到了传递数据的 ...

  10. Thread message loop for a thread with a hidden window? Make AllocateHwnd safe

    Thread message loop for a thread with a hidden window? I have a Delphi 6 application that has a thre ...