需求
监听天气数据,一旦数据改变,则更新布告板的内容。数据有:温度、湿度、气压
被观察者,也称为主题,Observable,(Subject)
/**
* 主题接口,所有主题接口都应该实现此接口
*/
public interface Subject
{
/**
* 注册观察者
*/
public void registerObserver(Observer o);
/**
* 删除观察者
*/
public void removeObserver(Observer o);
/**
* 当主题状态改变的时候,会调用此方法,通知所有的观察者
*/
public void notifyObservers();
}
/**
* 处理气象站数据的类,实现了主题Subject接口,用来接收气象站的信息,并通知所有的观察者
*/
public class WeatherData implements Subject
{
// 用来记录观察者
private ArrayList<Observer> observers = new ArrayList<Observer>();
private float temperature;
private float humidity;
private float pressure;
public void registerObserver(Observer o)
{
observers.add(o);
}
public void removeObserver(Observer o)
{
observers.remove(o);
}
/**
* 把状态告诉每一个观察者,观察者们都实现了update方法,所有我们知道如何通知他们
*/
public void notifyObservers()
{
for (Observer observer : observers)
{
observer.update(temperature, humidity, pressure);
}
}
/**
* 当气象站数据更新的时候,此方法被调用
*/
public void measurementsChanged()
{
notifyObservers();
}
/**
* 由于是模拟气象站,因此通过此方法模拟气象站调用measurementsChanged()方法
*/
public void setMeasurements(float temperature, float humidity,
float pressure)
{
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
// 省略 get
}
观察者(Observer)与布告板
/**
* 观察者接口,所有观察者都应该实现此接口
*/
public interface Observer
{
/**
* 所有的观察者都必须实现的方法,当主题状态变化时,调用此方法
*
* @param temp 温度
* @param humidity 湿度
* @param pressure 气压
*/
public void update(float temp, float humidity, float pressure);
}
/**
* 布告板接口,所有的气象布告板都需要实现此接口
*/
public interface DisplayElement
{
/**
* 当布告板需要显示时,调用此方法
*/
public void display();
}
/**
* 状况布告板
*/
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;
// 显示布告板,设置数据的显示方式,可以有很多方式,比如MVC
display();
}
/**
* 当布告板需要显示时,调用此方法
*/
public void display()
{
System.out.println("Current conditions: " + temperature
+ "F degrees and " + humidity + "% humidity");
}
}
测试
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);
}
观察者模式的定义:
定义了对象间的一对多依赖,当一个对象状态改变时,所以依赖者都会收到通知并自动更新
设计原则 4
让交互对象松耦合,降低对象的互相依赖,彼此不知道对方的细节,但是可以交互。
观察者:Observer
被观察者:Observable,(Subject)
订阅报纸的例子
Java 也有内置的观察者模式
应用了哪些设计原则
- 组合:观察者是通过运行时注册到被观察者的
- 针对接口:观察者和被观察者都是实现了对应的接口,注册和通知都是接口来进行的,松耦合
- 抽出会改变的部分,和不变的分开来:被观察者的状态会改变,观察者的数量和类型会改变,但是被观察者本身不用变,只需要关注各自状态的改变
注意
观察者被通知的次序是未知的
网友评论