观察者模式:定义了对象之间的一对多的依赖,这样一来,当一个对象改变状态时,他的所有者就会立刻接到通知并自动更新。
观察者模式定义了一系列对象之间的一对多关系。
当一个对象改变状态,当其他依赖者都会收到通知。
实现观察者模式的方法不止一种,但是以包含Subject与Observer接口的类的设计最为常见。
这和一对多的关系有何关联?
利用观察者模式,主题是具有状态的对象,并且可以控制这些状态。也就是说,有“一个”具有状态的主题。
另一方面,观察者使用这些状态,虽然这些状态并不属于他们。有许多的观察者,依赖主题来告诉他们状态
何时改变了。这就产生了一个关系:“一个”主题对“多个”观察者的关系。
期间的依赖是如何产生的?
因为主题是真正拥有数据的人,观察者是主题的依赖者,在数据变化更新,这样比起让许多对象控制一份数据来,可以得到更干净OO设计。
观察者模式定义了一系列对象之间的一对多关系。
当一个对象改变状态,当其他依赖者都会收到通知。
实现观察者模式的方法不止一种,但是以包含Subject与Observer接口的类的设计最为常见。
这和一对多的关系有何关联?
利用观察者模式,主题是具有状态的对象,并且可以控制这些状态。也就是说,有“一个”具有状态的主题。
另一方面,观察者使用这些状态,虽然这些状态并不属于他们。有许多的观察者,依赖主题来告诉他们状态
何时改变了。这就产生了一个关系:“一个”主题对“多个”观察者的关系。
期间的依赖是如何产生的?
因为主题是真正拥有数据的人,观察者是主题的依赖者,在数据变化更新,这样比起让许多对象控制一份数据来,可以得到更干净OO设计。
设计原则:为了交互对象之间的松耦合设计而努力
Demo:
业务场景:
建立一个应用,有三种布告板,分别显示目前的状况、气象统计及简单的预报。
当WeatherObject对象获得最新的测量数据时,三种布告板必须实时更新。
这是一个可以扩展的气象站,其他开发人员可以写出自己的气象布告板,并插入到应用中。
package cn.partner4java.weather;
/**
* 主业务类(管理观察员、并负责调用观察员)
* @author partner4java
*
*/
public interface Subject {
/**
* 注册观察员
* @param observer 观察员
*/
public void registerObserver(Observer observer);
/**
* 删除观察员
* @param observer 观察员
*/
public void removeObserver(Observer observer);
/**
* 通知所有的观察者
*/
public void notifyObserver();
}
package cn.partner4java.weather;
/**
* 布告板
* (如:目前状况布告板、统计布告板、预测布告板)
* @author partner4java
*
*/
public interface DisplayElement {
/**
* 布告调用方法
*/
public void display();
}
package cn.partner4java.weather;
/**
* 观察员(气象发生改变时,被调用的对象)
* @author partner4java
*
*/
public interface Observer {
/**
* 所有的观察者都必须实现这个方法,以实现观察者接口
* @param temperature 温度
* @param humidity 湿度
* @param pressure 气压
*/
public void update(float temperature,float humidity,float pressure);
}
package cn.partner4java.weather.impl;
import java.util.ArrayList;
import java.util.List;
import cn.partner4java.weather.Observer;
import cn.partner4java.weather.Subject;
/**
* 气象数据获取类
* 主业务类(管理观察员、并负责调用观察员)
* 实现主体接口
* @author partner4java
*
*/
public class WeatherData implements Subject {
/** 观察者列表 */
private List<Observer> observers;
/** 温度 */
private float temperature;
/** 湿度 */
private float humidity;
/** 气压 */
private float pressure;
public WeatherData(){
observers = new ArrayList<Observer>();
}
@Override
public void notifyObserver() {
for(int i=0;i<observers.size();i++){
Observer observer = observers.get(i);
observer.update(temperature, humidity, pressure);
}
}
@Override
public void registerObserver(Observer observer) {
int i = observers.indexOf(observer);
if(i == -1){
observers.add(observer);
}
}
@Override
public void removeObserver(Observer observer) {
int i = observers.indexOf(observer);
if(i >= 0){
observers.remove(i);
}
}
/**
* 当从气象站得到更新观测值时,我们通知观察者
*/
public void measurementsChanged(){
notifyObserver();
}
/**
* 设置气象改变数据
* @param temperature 温度
* @param humidity 湿度
* @param pressure 气压
*/
public void setMeasurements(float temperature,float humidity,float pressure){
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
public List<Observer> getObservers() {
return observers;
}
public void setObservers(List<Observer> observers) {
this.observers = observers;
}
public float getTemperature() {
return temperature;
}
public void setTemperature(float temperature) {
this.temperature = temperature;
}
public float getHumidity() {
return humidity;
}
public void setHumidity(float humidity) {
this.humidity = humidity;
}
public float getPressure() {
return pressure;
}
public void setPressure(float pressure) {
this.pressure = pressure;
}
}
package cn.partner4java.weather.impl;
import cn.partner4java.weather.DisplayElement;
import cn.partner4java.weather.Observer;
import cn.partner4java.weather.Subject;
/**
* 目前状况布告板
* @author partner4java
*
*/
public class CurrentConditionsDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
private Subject weatherData;
public CurrentConditionsDisplay(Subject weatherData){
this.weatherData = weatherData;
this.weatherData.registerObserver(this);
}
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
display();
}
@Override
public void display() {
System.out.println("CurrentConditionsDisplay: temperature-" + temperature +
" humidity-" + humidity);
}
}
package cn.partner4java.weather.impl;
import cn.partner4java.weather.DisplayElement;
import cn.partner4java.weather.Observer;
/**
* 未来天气预告版
* @author partner4java
*
*/
public class ForecastDisplay implements DisplayElement, Observer {
/** 当前气压 */
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.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");
}
}
@Override
public void update(float temperature, float humidity, float pressure) {
lastPressure = currentPressure;
currentPressure = pressure;
display();
}
}
package cn.partner4java.weather.impl;
import cn.partner4java.weather.DisplayElement;
import cn.partner4java.weather.Observer;
/**
* 统计状态布告
* @author partner4java
*
*/
public class StatisticsDisplay implements DisplayElement, Observer {
/** 最高温度 */
private float maxTemp = 0.0f;
/** 最低温度 */
private float minTemp = 200;
/** 记录总温度 */
private float tempSum = 0.0f;
/** 温度读取次数 */
private int countReadings;
private WeatherData weatherData;
public StatisticsDisplay(WeatherData weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void display() {
System.out.println("StatisticsDisplay: maxTemp-" +
maxTemp + " minTemp-" + minTemp + " averageTemp-" +
tempSum/countReadings);
}
@Override
public void update(float temperature, float humidity, float pressure) {
tempSum += temperature;
countReadings++;
if(temperature < minTemp){
minTemp = temperature;
}else if(temperature > maxTemp){
maxTemp = temperature;
}
display();
}
}
package cn.partner4java.weather.test;
import cn.partner4java.weather.impl.CurrentConditionsDisplay;
import cn.partner4java.weather.impl.ForecastDisplay;
import cn.partner4java.weather.impl.StatisticsDisplay;
import cn.partner4java.weather.impl.WeatherData;
/**
* 气象站测试(启动气象站)
* @author partner4java
*
*/
public class WeatherStation {
/**
* @param args
*/
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
weatherData.setMeasurements(80, 234, 20.4f);
weatherData.setMeasurements(56, 232, 20.4f);
weatherData.setMeasurements(34, 123, 20.4f);
}
}