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。