学习:设计模式之观察者模式
来源:互联网 发布:2017年网络诈骗案 编辑:程序博客网 时间:2024/05/22 16:53
本文来自www.lanttor.org
Internet气象站
经验有一个模式可以帮助你的对象知悉现况,不会错过对象感兴趣的事。对象甚至在运行时可决定是否要继续被通知。观察者模式是JDK中使用最多的模式之一。非常有用。
气象监测应用的概况
认识观察者模式
报纸和杂志的订阅是怎么回事:
- 报社的业务是出版报纸;
- 向某家报社订阅报纸,只要你是他们的用户,你就会收到新报纸;
- 你不想看报纸的话,取消订阅,他们就不会再送新报纸来;
- 只要报社运营,就会一直有人(或单位)向他们订阅报纸或取消订阅。
出版者 + 订阅者 = 观察者模式
出版者改称为“主题”(subject);订阅者改称为“观察者”(Observer)。
观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变时,它的所有依赖者都会收到通知并自动更新。
定义观察者模式
实现观察者模式的方法不只一种,但是以包含Subject和Observer接口的类设计的做法最常见。
设计原则为了交互对象之间的松耦合设计而努力。当两个对象之间松耦合,他们依然可以交互,但是不太清楚彼此的细节。
观察者模式提供了一种对象设计,让主题和观察者之间松耦合。
松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的互相依赖降低到了最低。
设计气象站
气象站代码
Subject.java代码:
package headfirst.observer.weather;
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
Observer.java代码:
package headfirst.observer.weather;
public interface Observer {
public void update(float temp, float humidity, float pressure);
}
DisplayElement.java代码:
package headfirst.observer.weather;
public interface DisplayElement {
public void display();
}
WeatherData.java代码:
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;
}
}
CurrentConditionsDisplay.java代码:
package headfirst.observer.weather;
public class CurrentConditionsDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
private Subject weatherData;
public CurrentConditionsDisplay(Subject 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");
}
}
ForecastDisplay.java代码:
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");
}
}
}
StaticsDisplay.java代码:
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);
}
}
HeatIndexDisplay.java代码:
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);
}
}
测试结果
测试代码(WeatherStationHeatIndex.java):
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);
}
}
结果:
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!
Heat index is 82.95535
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
Heat index is 86.90124
Current conditions: 78.0F degrees and 90.0% humidity
Avg/Max/Min temperature = 80.0/82.0/78.0
Forecast: More of the same
Heat index is 83.64967
使用java内置的观察者模式
java.util包内包含最基本的Observer接口和Observable类。
导入Observer/Observable:
import java.util.Observable;
import java.util.Observer;
使用Observable类代替之前的Subject接口;Observable是类,所以WeatherData继承Observable。
Observable如何送出通知:
先调用setChanged()方法,标记状态已经改变的事实;
然后调用notifyObservers()/notifyObservers(Object arg)
Observer如何接收通知:
观察者实现了update()方法,只是方法的签名更改为update(Observable o, Object arg)
在update()中,先确定观察者属于WeatherData类型,然后利用getter方法获取相应的更新数据,然后调用display()。
利用内置的观察者模式重做气象站
WeatherData.java代码:
package headfirst.observer.weatherobservable;
import java.util.Observable;
import java.util.Observer;
public class WeatherData extends Observable {
private float temperature;
private float humidity;
private float pressure;
public WeatherData() { }
public void measurementsChanged() {
setChanged();
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;
}
}
CurrentConditionsDisplay.java代码:
package headfirst.observer.weatherobservable;
import java.util.Observable;
import java.util.Observer;
public class CurrentConditionsDisplay implements Observer, DisplayElement {
Observable observable;
private float temperature;
private float humidity;
public CurrentConditionsDisplay(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
public void update(Observable obs, Object arg) {
if (obs instanceof WeatherData) {
WeatherData weatherData = (WeatherData)obs;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
}
public void display() {
System.out.println("Current conditions: " + temperature
+ "F degrees and " + humidity + "% humidity");
}
}
JDK Swing中观察者模式的使用
一个简单的Swing API:JButton。如果你观察一下JButton的超类AbstractButton,会看到许多增加与删除Listener的方法。这些方法可以让观察者感应到Swing组件的不同类型事件。比方说,ActionListener让你“倾听”可能发生在按钮上的动作,例如按下按钮。这些方法就是典型的观察者模式的使用。
总结
- 观察者模式定义了对象之间一对多的关系。
- 主题(也就是可观察者)用一个共同的接口来更新观察者。
- 观察者和可观察者之间用松耦合方式结合。可观察者不知道观察者的细节,只知道观察者实现了观察者接口。
- 使用此模式时,你可从被观察者处推(push)或拉(pull)数据。(推的方式被认为更正确)。
- 有多个观察者时,不可以依赖特定的通知次序。
- Java有多种观察者模式的实现,包括了通用的java.util.Observable和java.util.Observer。
- 要注意java.util.Observable实现上所带来的问题。
- 如果有必要的话,可以实现自己的Observable,这并不困难。
- Swing大量使用观察者模式,许多GUI框架也是如此。
- 此模式也被应用在许多地方,例如:JavaBeans,RMI
- 学习笔记 ---- 设计模式之观察者模式
- 设计模式之观察者模式学习笔记
- 设计模式之观察者模式学习
- 设计模式学习笔记之观察者模式
- 设计模式学习之观察者模式
- 设计模式之观察者模式案例学习
- 设计模式学习之观察者模式
- 学习:设计模式之观察者模式
- C++ 设计模式学习之 观察者模式
- 设计模式学习笔记之观察者模式
- 设计模式学习之观察者模式
- Android设计模式学习之观察者模式
- 设计模式学习笔记之观察者模式
- 设计模式学习之—观察者模式
- 设计模式学习之路-观察者模式
- 设计模式学习笔记之观察者模式
- JavaScript学习之设计模式->观察者模式
- Android设计模式学习之观察者模式
- Maven教程文档
- Android 好资源推荐
- eCos仿真目标机(3)――运行eCos应用
- check 切换,,radio获取 ,,jquery代码
- android DialogFragment简单应用
- 学习:设计模式之观察者模式
- AngularJS scope
- 中宗反正後의 國政 (朝鮮歷史 韓長庚)
- 学习中
- AdaBoost人脸检测原理
- 试试怎么发代码
- 金额输入的正则表达式
- systemtap初试用
- Java字节码(.class文件)的代码解析