觀察者模式 觀察者模式:定義了對象之間的一對多依賴,這樣一來,當一個對象改變狀態時,它的所有依賴者都會收到通知并自動更新。 上面是書中對觀察者模式的定義。從定義中我們大體可以讀懂這個模式的基本思想:一個對象狀態改變,會通知依賴(訂閱它的對象)它的所有對象。這就好比我們生活中的報紙訂閱模式: 1) 報社的業務就是出版報紙。 2) 向某家報社訂閱報紙,只要他們有新報紙出版,就會給你送來。只要你是他們的訂戶,你就會一直收到新報紙。 3) 當你不想再看報紙的時候,取消訂閱,他們就不會再送新報紙來。 4) 只要報社還在運營,就會一直有人(或單位)向他們訂閱報紙或取消訂閱報紙。 你可以這樣理解: 出版者 + 訂閱者 = 觀察者模式 其中的出版者在模式中稱為【主題】(Subject),訂閱者改稱為【觀察者】Observer。如圖1所示:
Figure 1 主題訂閱圖 實現觀察者模式的方法不只一種,但是以包含Subject與Observer接口的 類設計的做法最常見。下面我們基于接口來說明觀察者模式,類圖如圖2所示:
Figure 2觀察者模式類圖 從上圖我們可以知道,這種設計可以使兩者實現松耦合。因為,關于觀察者的一切,主題只知道觀察者實現了某個接口(Observer接口)。主題不需要知道觀察者的具體實現類是誰、做了些什么等。如果我們要增加新的觀察者,只需要新增的觀察者實現了該接口,并注冊到主題中即可。 下面我們拿書中的例子來具體說明: 現有一個氣象站會實時抓取天氣的相關信息,比如溫度、濕度、氣壓等,現在要建一些公告板來分別顯示這些信息,具體如下圖3所示:
Figure 3氣象參數圖 圖中的WeatherData對象負責跟蹤這些氣象數據,具體如何跟蹤這里跟我們無關,它取得最新數據會更新自己的狀態。之后相關的公告板會實時的顯示這些信息。那么這顯然是一個觀察者模式的相關例子,WeatherData—Subject , 公告板—Observer。代碼如下所示: //Subject
//WeatherData
/** * @ClassName: WeatherData * @Description: Subject 具體的實現類 * @author 春天畫花卉校長 * @date 2017年2月19日 下午11:52:50 * */public class WeatherData implements Subject{ PRivate ArrayList<Observer> observers; private float temperature; private float humidity; private float pressure; public WeatherData() { observers = new ArrayList<Observer>(); } @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(o); } } @Override public void notifyObservers() { for(int i = 0; i < observers.size(); i++){ Observer observer = observers.get(i); observer.update(temperature, humidity, pressure); } } //當從氣象站得到更新數據時,我們通知觀察者 public void measurementsChanged() { this.notifyObservers(); } public void setMeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; this.measurementsChanged(); }}//Observer
/** * @ClassName: Observer * @Description: Observer Interface* @author 春天畫花卉校長 * @date 2017年2月19日 下午11:45:04 * */public interface Observer { //所有觀察者都必須實現update()方法,以實現觀察者接口。當氣象值改變時,主題會把這些狀態當作參數,推給觀察者 public void update(float temp, float humidity, float pressure);}//CurrentConditionsDisplay
/** * @ClassName: CurrentConditionsDisplay * @Description: Observer 具體的實現類 * @author 春天畫花卉校長 * @date 2017年2月20日 上午12:00:01 * */public class CurrentConditionsDisplay implements Observer { private float temperature; private float humidity; private Subject weatherData; public CurrentConditionsDisplay(Subject weatherData) { super(); this.weatherData = weatherData; weatherData.registerObserver(this);//構造器需要weatherData對象作為注冊之用 } public CurrentConditionsDisplay() { } @Override public void update(float temp, float humidity, float pressure) { this.temperature = temp; this.humidity = humidity; System.out.println("Current conditions:" + temperature + "F degrees and " + humidity + "% humidity."); }}//Main
/** * @ClassName: WeatherStation * @Description: 測試主類* @author 春天畫花卉校長 * @date 2017年2月20日 上午12:04:31 * */public class WeatherStation { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData); weatherData.setMeasurements(80, 79, 30.4f); }}//運行結果
其實在java API有內置的觀察者模式。Java.util包(Package)內包含最基本的Observer接口與Observable類,這和Subject接口和Observer接口很相似。甚至對消息的通知提供了推和拉兩種模式,推就是主題會把所有的數據都給觀察者,而拉則是有觀察者自己去拉取自己所要的數據。 在Observable類中基本的對觀察者的增、刪、通知觀察者的方法都已經實現,你所要做的就是繼承這個類。
新聞熱點
疑難解答