设计模式学习 -- 观察者模式 (Observer Pattern)
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}
5. 定义四个布告板类实现观察者接口和布告板接口
package observerPattern;
/**
观察者类实现观察者接口和显示板接口
@author wwj
*/
public class CurrentConditionDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
private Subject weathderData;
public CurrentConditionDisplay(Subject weathderData) {
this.weathderData = weathderData;
weathderData.registerObserver(this); //注册
}
@Override
public void display() {
System.out.println("Current coditions: " + temperature + "F degress and " + humidity + "% humidity");
}
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
display();
}
}
package observerPattern;
/**
天气统计布告板
@author wwj
*/
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);
}
@Override
public void display() {
System.out.println("Avg/Max/Min temperature = " + (tempSum / numReadings) + "/" + maxTemp + "/" + minTemp);
}
@Override
public void update(float temp, float humidity, float pressure) {
tempSum += temp;
numReadings++;
if(temp > maxTemp) {
maxTemp = temp;
}
if(temp < minTemp) {
minTemp = temp;
}
display();
}
}
package observerPattern;
/**
天气预报布告板
@author wwj
*/
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);
}
@Override
public void display() {
System.out.println("Forcast:");
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");
}
}
@Override
public void update(float temp, float humidity, float pressure) {
lastPressure = currentPressure;
currentPressure = pressure;
display();
}
}
package observerPattern;
/**
酷热指数布告板
@author wwj
注:那个计算酷热指数的公式不必深究
*/
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);
}
}
6. 来吧,开始测试
package observerPattern;
/**
测试类
@author wwj
*/
public class WeatherStation {
public static void main(String[] args) {
//建立一个 WeatherData 对象
WeatherData weatherData = new WeatherData();
//第一个布告板
CurrentConditionDisplay currentDisplay = new CurrentConditionDisplay(
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);
}
}
7. 测试结果:
Current coditions: 80.0F degress and 65.0% humidity
Avg/Max/Min temperature = 80.0/80.0/80.0
Forcast:
Improving weather on the way!
Heat index is 82.95535
Current coditions: 82.0F degress and 70.0% humidity
Avg/Max/Min temperature = 81.0/82.0/80.0
Forcast:
Watch out for cooler, rainy weather
Heat index is 86.90124
Current coditions: 78.0F degress and 90.0% humidity
Avg/Max/Min temperature = 80.0/82.0/78.0
Forcast:
more of the same
Heat index is 83.64967
以上的观察者模式实现是通过主题以“推”的方式通知观察者们,观察者可以在一次通知中一口气得到所有东西。
因为观察者与主题发生了争吵,观察者有自己的想法,希望能“拉”走主题的状态,然而 Java 内置的 Observer 模式就支持这样,下面来看看吧。
1. 继承 Observable 类的 WeatherData(不再需要自定义接口了,但这样真的好吗?)
package weatherObservable;
import java.util.Observable;
/**
使用 Java 内置的观察者模式
@author wwj
*/
public class WeatherData extends Observable {
private float temperature;
private float humidity;
private float pressure;
/**
我们的构造器不再需要为了记住观察者们而建立数据结构了
*/
public WeatherData(){}
public void measurementsChanged() {
setChanged(); //Observable 类方法
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;
}
}
2. 4 个布告板中的代码稍微发生了点变化
package weatherObservable;
import java.util.Observable;
import java.util.Observer;
/**
实现 Java 内置的观察者接口,布告板不变
@author wwj
*/
public class CurrentConditionDisplay implements Observer, DisplayElement{
Observable observable;
private float temperature;
private float humidity;
public CurrentConditionDisplay(Observable observable) {
this.observable = observable;
observable.addObserver(this); //登记为观察者
}
@Override
public void display() {
System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
}
/**
在这个方法当中,先确定可观察者属于 WeatherData 类型,然后利用 getter 方法获取温度和温度测量值,最后调用 display();
*/
@Override
public void update(Observable obs, Object arg) {
if(obs instanceof WeatherData) {
WeatherData weatherData = (WeatherData) obs;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
}
}
package weatherObservable;
import java.util.Observable;
import java.util.Observer;
/**
天气预报布告板
@author wwj
*/
public class ForecastDisplay implements Observer, DisplayElement {
private Observable observable;
private float currentPressure = 29.92f; //当前气压
private float lastPressure; //以往气压
public ForecastDisplay(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
@Override
public void display() {
System.out.println("Forcast:");
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");
}
}
@Override
public void update(Observable o, Object arg) {
if (o instanceof WeatherData) {
WeatherData weatherData = (WeatherData)observable;
lastPressure = currentPressure;
currentPressure = weatherData.getPressure();
display();
}
}
}
package weatherObservable;
import java.util.Observable;
import java.util.Observer;
/**
天气统计布告板
@author wwj
*/
public class StatisticsDisplay implements Observer, DisplayElement {
private float maxTemp = 0.0f;; //最大温度
private float minTemp = 200; //最小温度
private float tempSum = 0.0f; //统计温度和
private int numReadings; //统计温度次数
private Observable observable;
public StatisticsDisplay(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
@Override
public void display() {
System.out.println("Avg/Max/Min temperature = " + (tempSum / numReadings) + "/" + maxTemp + "/" + minTemp);
}
@Override
public void update(Observable obs, Object arg) {
if(obs instanceof WeatherData) {
WeatherData weatherData = (WeatherData)obs;
float temp = weatherData.getTemperature();
tempSum += temp;
numReadings++;
if (temp > maxTemp) {
maxTemp = temp;
}
if (temp < minTemp) {
minTemp = temp;
}
display();
}
}
}
package weatherObservable;
import java.util.Observable;
import java.util.Observer;
/**
酷热指数布告板
@author wwj
注:那个计算酷热指数的公式不必深究
*/
public class HeatIndexDisplay implements Observer, DisplayElement {
float heatIndex = 0.0f;
private WeatherData weatherData;
private Observable observable;
public HeatIndexDisplay(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
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);
}
@Override
public void update(Observable obs, Object arg) {
if(obs instanceof WeatherData) {
WeatherData weatherData = (WeatherData)observable;
float t = weatherData.getTemperature
();
float rh = weatherData.getHumidity();
heatIndex = computeHeatIndex(t, rh);
}
display();
}
}
3. 测试类不变
package weatherObservable;
/**
测试类
@author wwj
*/
public class WeatherStation {
public static void main(String[] args) {
//建立一个 WeatherData 对象
WeatherData weatherData = new WeatherData();
//第一个布告板
CurrentConditionDisplay currentDisplay = new CurrentConditionDisplay(
weatherData);
StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
HeatIndexDisplay heatIndexDisplay = new HeatIndexDisplay(weatherData);
评论