學習設計模式已經有段時間了,這是總結的第一篇博客,文中有錯誤、漏洞之處,望各位支出,改正。
觀察者模式
一、基本定義
何謂觀察者模式?觀察者模式定義了對象之間的一對多依賴關系,這樣一來,當一個對象改變狀態時,它的所有依賴者都會收到通知並且自動更新。
在這里,發生改變的對象稱之為觀察目標,而被通知的對象稱之為觀察者。一個觀察目標可以對應多個觀察者,而且這些觀察者之間沒有相互聯系,所以么可以根據需要增加和刪除觀察者,使得系統更易於擴展。
觀察者模式又稱為發布-訂閱模式。
二、基本結構
首先先看觀察者模式的UML類圖。
分析:
Subject:目標。他把所有對觀察者對戲的引用保存在一個聚集里,每一個主題都可以有多個觀察者。
Observer:觀察者。為所有的具體觀察者定義一個接口,在得到主題的通知時能夠及時的更新自己。
ConcreteSubject:具體主題。將有關狀態存入具體觀察者對象。在具體主題發生改變時,給所有的觀察者發出通知。
ConcreteObserver:具體觀察者。實現抽象觀察者角色所要求的更新接口,以便使本身的狀態與主題狀態相協調。
三、實現觀察者模式
情景是這樣的:在氣象觀測站中,它能夠追蹤目前的天氣狀況,包括溫度、適度、氣壓。需要實現一個布告板,能夠分別顯示目前的狀態,氣象統計和簡單的預報。當氣象站中獲取最新的測量數據時,三種布告板必須實時更新。
下面是這個案例的設計圖:
編碼實現:
主題接口 Subject.java
1 public interface Subject { 2 /** 3 * 注冊觀察者 4 * @param observer 5 */ 6 public void registerObserver(Observer observer); 7 8 /** 9 * 刪除觀察者 10 * @param observer 11 */ 12 public void removeOberver(Observer observer); 13 14 /** 15 * 當主題狀態發生改變時,這個方法需要被調用,以通知所有觀察者 16 */ 17 public void notifyObserver(); 18 }
觀察者接口 Observer.java
1 public interface Observer { 2 public void update(float temp,float humidity,float pressure); 3 }
布告板顯示接口 DisplayElement.java
1 public interface DisplayElement { 2 public void display(); 3 }
WeatherData實現主題接口 WeatherData.java
1 public class WeatherData implements Subject{ 2 private List<Observer> observers; 3 private float tempterature; 4 private float pressure; 5 private float humidity; 6 7 public WeatherData(){ 8 observers = new ArrayList<Observer>(); 9 } 10 11 @Override 12 public void notifyObserver() { 13 for(int i = 0; i < observers.size();i++){ 14 Observer observer = observers.get(i); 15 observer.update(tempterature, humidity, pressure); 16 } 17 } 18 19 @Override 20 public void registerObserver(Observer observer) { 21 observers.add(observer); 22 } 23 24 @Override 25 public void removeOberver(Observer observer) { 26 int i = observers.indexOf(observer); 27 if(i >= 0){ 28 observers.remove(i); 29 } 30 } 31 32 /** 33 * 氣象站得到更新的觀測數據時,通知觀察者 34 */ 35 public void measurementChanged(){ 36 notifyObserver(); 37 } 38 39 public void setMeasurements(float temperature,float humidity,float pressure){ 40 this.tempterature = temperature; 41 this.humidity = humidity; 42 this.pressure = pressure; 43 measurementChanged(); 44 } 45 }
布告板 CurrentCondituonDisplay.java
1 public class CurrentConditionsDisplay implements Observer,DisplayElement{ 2 private float temperature; 3 private float humidity; 4 private Subject weatherData; 5 6 public CurrentConditionsDisplay(Subject weatherData){ 7 this.weatherData = weatherData; 8 weatherData.registerObserver(this); //注冊觀察者 9 } 10 11 public void update(float temp, float humidity, float pressure) { 12 this.temperature = temp; 13 this.humidity = humidity; 14 display(); 15 } 16 17 @Override 18 public void display() { 19 System.out.println("Current conditions:"+temperature+"F degrees and "+humidity+"% humidity"); 20 } 21 22 }
測試程序 WeatherStation
1 public class WeatherStation { 2 3 public static void main(String[] args) { 4 WeatherData weatherData = new WeatherData(); 5 6 CurrentConditionsDisplay conditionsDisplay = new CurrentConditionsDisplay(weatherData); 7 8 weatherData.setMeasurements(80, 65, 30.4f); 9 weatherData.setMeasurements(82, 70, 29.2f); 10 weatherData.setMeasurements(78, 78, 40.4f); 11 } 12 }
運行過程
四、觀察者模式的優缺點
優點:
1、當兩個對象之間送耦合,他們依然可以交互,但是不太清楚彼此的細節。觀察者模式提供了一種對象設計,讓主題和觀察者之間送耦合。主題所知道只是一個具體的觀察者列表,每一個具體觀察者都符合一個抽象觀察者的接口。主題並不認識任何一個具體的觀察者,它只知道他們都有一個共同的接口。
2、觀察者模式支持“廣播通信”。主題會向所有的觀察者發出通知。
3、觀察者模式符合“開閉原則”的要求。
缺點:
1、如果一個被觀察者對象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間。
2、 如果在觀察者和觀察目標之間有循環依賴的話,觀察目標會觸發它們之間進 行循環調用,可能導致系統崩潰。
3、 觀察者模式沒有相應的機制讓觀察者知道所觀察的目標對象是怎么發生變化的,而僅僅只是知道觀察目標發生了變化。
五、觀察者模式的適用場所
1、一個抽象模型有兩個方面,其中一個方面依賴於另一個方面。將這些方面封裝在獨立的對象中使它們可以各自獨立地改變和復用。
2、一個對象的改變將導致其他一個或多個對象也發生改變,而不知道具體有多少對象將發生改變,可以降低對象之間的耦合度。
3、一個對象必須通知其他對象,而並不知道這些對象是誰。需要在系統中創建一個觸發鏈,A對象的行為將影響B對象,B對象的行為將影響C對象……,可以使用觀察者模式創建一種鏈式觸發機制。
總結
1、觀察者模式定義了對象之間的一對多關系。多個觀察者監聽同一個被觀察者,當該被觀察者的狀態發生改變時,會通知所有的觀察者。
2、觀察者模式中包含四個角色。主題,它指被觀察的對象。具體主題是主題子類,通常它包含有經常發生改變的數據,當它的狀態發生改變時,向它的各個觀察者發出通知;觀察者,將對觀察主題的改變做出反應;具體觀察者中維護一個指向具體目標對象的引用,它存儲具體觀察者的有關狀態,這些狀態需要和具體目標的狀態保持一致。
3、主題用一個共同的接口來更新觀察者。
4、觀察者與被觀察者之間用松耦合方式結合。
5、有多個觀察者時,不可以依賴特定的通知次序。
6、使用觀察者模式,可以從被觀察者處推或者拉數據。
該讀書筆記的代碼和部分語句均來自《Head First 設計模式》