認識觀察者模式
我們看看報紙和雜志的訂閱是怎麼回事:
1.報社的業務就是出版報紙。
2.向某家報社訂閱報紙,隻要他們有新報紙出版,就會給你送
來。隻要你是他們的訂戶,你就會一直收到新報紙。
3.當你不想再看報紙的時候,取消訂閱,他們就不會再送新報
紙來。
4.隻要報社還在營運,就會一直有人(或機關)向他們訂閱報
紙或取消訂閱報紙。
使用JDK内置的觀察者模式的一個例子
可觀察者
import java.util.Observable; //類
import java.util.Observer; //接口
public class WeatherData extends Observable {
private float temperature;
private float humidity;
private float pressure;
public WeatherData() { }
public void measurementsChanged() {
setChanged();
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;
}
}
可觀察者(釋出消息給觀察者可以是可觀察者者固定推送,或者是觀察者根據需要适時拉取)
import java.util.Observable;
import java.util.Observer;
public class CurrentConditionsDisplay implements Observer, DisplayElement {
Observable observable;
private float temperature;
private float humidity;
public CurrentConditionsDisplay(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
public void update(Observable obs, Object arg) {
if (obs instanceof WeatherData) {
WeatherData weatherData = (WeatherData)obs;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
}
public void display() {
System.out.println("Current conditions: " + temperature
+ "F degrees and " + humidity + "% humidity");
}
}
接口DisplayElement
public interface DisplayElement {
public void display();
}
Java内置的觀察者模式如何運作
如何把對象變成觀察者……
如同以前一樣,實作觀察者接口(java.uitl.Observer),然後調用任何Observable對
象的addObserver()方法。不想再當觀察者時,調用deleteObserver()方法就可以了。
可觀察者要如何送出通知 ……
首先,你需要利用擴充java.util.Observable接口産生“可觀察者”類,然後,需要兩
個步驟:
1.先調用setChanged()方法,标記狀态已經改變的事實。(該方法根據需要調用,但是未調用該方法就調用notifyObervers(),觀察者不會“被通知”)
2.然後調用兩種notifyObservers()方法中的一個:
notifyObservers() 或 notifyObservers(Object arg)
觀察者如何接收通知 ……
update(Observable o, Object arg)
主題本身當作第一個變量,好讓觀察者知道是哪個主題通知它的,而第二個參數正是傳入notifyObservers()的資料對象。如果沒有說明 則為空。如果想要“推”資料給觀察者,可以把資料當做資料對象傳送給notifyObvers(args)方法,否則,觀察者就必須從可觀察者對象中“拉”對象。
使用内置觀察者模式的弊端
Observable是一個類
你已經從我們的原則中得知這不是一件好事,但是,這到底會造成什麼問題呢?
首先,因為Observable是一個“類”,你必須設計一個類繼承它。如果某類想同時
具有Observable類和另一個超類的行為,就會陷入兩難,畢竟Java不支援多重繼承。
這限制了Observable的複用潛力(而增加複用潛力不正是我們使用模式最原始的動
機嗎?)。
再者,因為沒有Observable接口,是以你無法建立自己的實作,和Java内置的
Observer API搭配使用,也無法将java.util的實作換成另一套做法的實作(比方說,
Observable将關鍵的方法保護起來
如果你能夠擴充java.util.Observable,那麼Observable“可能”可以符合你的需求。
否則,你可能需要像本章開頭的做法那樣自己實作這一整套觀察者模式。不管用
哪一種方法,反正你都已經熟悉觀察者模式了,應該都能善用它們。
如果你看看Observable API,你會發現setChanged()方法被保護起來了(被定義成
protected)。那又怎麼樣呢?這意味着:除非你繼承自Observable,否則你無法
建立Observable執行個體并組合到你自己的對象中來。這個設計違反了第二個設計原
則:“多用組合,少用繼承”。