1、定义:观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
通俗来说:举个报社(主题)和订阅报纸的家庭(观察者)例子。
-
报社的业务就是出版报纸。
-
向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来。只要你是他们的订户,你就会一直收到新报纸。
-
当你不想再看报纸的时候,取消订阅,他们就不会再送新报纸来。
-
只要报社还在运营,就会一直有人(或单位)向他们订阅报纸或取消订阅报纸。
2、实现观察者模式
(1)包含Subject接口和Observer接口
(2)Java内置的观察者模式,在java.util包下包含最基本的Observer接口与Observable类。
3、包含Subject接口和Observer接口的代码实现
业务场景:系统中的三个部分是气象站(获取实际气象数据的物理装置)、WeatherData对 象(追踪来自气象站的数据,并 更新布告板)和布告板(显示目前天气状况给用 户看)。 我们的工作就是建立一个应用,利用WeatherData对象取得数据,并 更新布告板:实时显示目前天气状况。
3.1、新建一个Sbuject主题接口
public interface Subject {
// 注册观察者
public void registerObserver(Observer o);
// 删除观察者
public void removeObserver(Observer o);
// 当主题状态改变时,通知所有观察者
public void notifyObservers();
}
3.2 新建Observer观察者接口
public interface Observer {
public void update(float temp, float humidity, float preessure);
}
3.3 新建DisplayElement ,布告版显示接口
public interface DisplayElement {
/*
DisplayElement接口只包含了一个方法, 也就是display()。当布告板需要显示时, 调用此方法。
*/
public void display();
}
3.4 创建具体的Subject类,实现Subject接口
public class WeatherData implements Subject {
private ArrayList observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
if (i > 0) {
observers.remove(i);
}
}
@Override
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();
}
}
3.5 创建具体的布告板(Observer)类,实现Observer接口和display接口,可更新布告板信息。
public class CurrentConditionsDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
private float pressure;
private Subject weatherData;
public CurrentConditionsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void display() {
System.out.println("Current conditions: " + temperature + " degrees and " + humidity + "% humidity and "
+ pressure + "% pressure" );
}
@Override
public void update(float temp, float humidity, float preessure) {
this.temperature = temp;
this.humidity = humidity;
this.pressure = preessure;
display();
}
}
3.6 最后,建立气象站类,当天气情况改变时候,看看输出结果。
/**
* @ClassName WeatherStation
* @Description 更新天气公告板
* @Author
* @Date 2018/11/7 14:51
*/
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentConditionDisplay = new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(50, 75, 43.4f);
}
}
输出结果:
Current conditions: 80.0 degrees and 65.0% humidity and 30.4% pressure
Current conditions: 50.0 degrees and 75.0% humidity and 43.4% pressure
4、要点:
-
观察者模式定义了对象之间一对多的关系。
-
主题(也就是可观察者)用一 个共同的接口来更新观察者 。
-
观察者和可观察者(主题)之间用松耦合方式结合(loosecoupling),可观察者不知道观察者的细节,只知道观察者实现 了观察者接口。
-
使用此模式时,你可从被观察 者处推(push)或拉(pull) 数据(然而,推的方式被认为 更“正确”)。
-
有多个观察者时,不可以依赖特定的通知次序。
-
Java有多种观察者模式的实 现,包括了通用的java.util. Observable。
-
要注意java.util.Observable(是一个类实现上所带来的一些问题)。
-
如果有必要的话,可以实现自 己的Observable,这并不难,不要害怕。
-
Swing大量使用观察者模式, 许多GUI框架也是如此。
-
观察者模式也被应用在许多地方, 例如:JavaBeans、RMI。