Java設計模式之觀察者模式



觀察者模式中,一個被觀察者管理所有相依於它的觀察者物件,並且在本身的狀態改變時主動發出通知。這通常通過呼叫各觀察者所提供的方法來實現。此種模式通常被用來實現事件處理系統。

角色
抽象被觀察者角色:把所有對觀察者對象的引用保存在一個集合中,每個被觀察者角色都可以有任意數量的觀察者。被觀察者提供一個接口,可以增加和刪除觀察者角色。一般用一個抽象類和接口來實現。
抽象觀察者角色:爲所有具體的觀察者定義一個接口,在得到主題的通知時更新自己。
具體被觀察者角色:在被觀察者內部狀態改變時,給所有登記過的觀察者發出通知。具體被觀察者角色通常用一個子類實現。
具體觀察者角色:該角色實現抽象觀察者角色所要求的更新接口,以便使本身的狀態與主題的狀態相協調。通常用一個子類實現。如果需要,具體觀察者角色可以保存一個指向具體主題角色的引用。

適用場景
1) 當一個抽象模型有兩個方面, 其中一個方面依賴於另一方面。將這二者封裝在獨立的對象中以使它們可以各自獨立地改變和複用。
2) 當對一個對象的改變需要同時改變其它對象, 而不知道具體有多少對象有待改變。
3) 當一個對象必須通知其它對象,而它又不能假定其它對象是誰。換言之, 你不希望這些對象是緊密耦合的。

應用
珠寶商運送一批鑽石,有黃金強盜準備搶劫,珠寶商僱傭了私人保鏢,警察局也派人護送,於是當運輸車上路的時候,強盜保鏢警察都要觀察運輸車一舉一動,
抽象的觀察者
[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. public interface Watcher  
  2. {  
  3.      public void update();  
  4. }  
抽象的被觀察者,在其中聲明方法(添加、移除觀察者,通知觀察者):
[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. public interface Watched  
  2. {  
  3.      public void addWatcher(Watcher watcher);  
  4.   
  5.      public void removeWatcher(Watcher watcher);  
  6.   
  7.      public void notifyWatchers();  
  8. }  
具體的觀察者
保鏢
[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. public class Security implements Watcher  
  2. {  
  3.      @Override  
  4.      public void update()  
  5.      {  
  6.           System.out.println(“運輸車有行動,保安貼身保護");  
  7.      }  
  8. }  
強盜
[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. public class Thief implements Watcher  
  2. {  
  3.      @Override  
  4.      public void update()  
  5.      {  
  6.           System.out.println(“運輸車有行動,強盜準備動手");  
  7.      }  
  8. }  
警察
[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. public class Police implements Watcher  
  2. {  
  3.      @Override  
  4.      public void update()  
  5.      {  
  6.           System.out.println(“運輸車有行動,警察護航");  
  7.      }  
  8. }  
具體的被觀察者
[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. public class Transporter implements Watched  
  2. {  
  3.      private List<Watcher> list = new ArrayList<Watcher>();  
  4.   
  5.      @Override  
  6.      public void addWatcher(Watcher watcher)  
  7.      {  
  8.           list.add(watcher);  
  9.      }  
  10.   
  11.      @Override  
  12.      public void removeWatcher(Watcher watcher)  
  13.      {  
  14.           list.remove(watcher);  
  15.      }  
  16.   
  17.      @Override  
  18.      public void notifyWatchers(String str)  
  19.      {  
  20.           for (Watcher watcher : list)  
  21.           {  
  22.                watcher.update();  
  23.           }  
  24.      }  
  25.   
  26. }  
測試類
[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. public class Test  
  2. {  
  3.      public static void main(String[] args)  
  4.      {  
  5.           Transporter transporter = new Transporter();  
  6.   
  7.           Police police = new Police();  
  8.           Security security = new Security();  
  9.           Thief thief = new Thief();  
  10.   
  11.           transporter.addWatcher(police);  
  12.           transporter.addWatcher(security);  
  13.           transporter.addWatcher(security);  
  14.   
  15.           transporter.notifyWatchers();  
  16.      }  
  17. }  

我推你拉
例子中沒有關於數據和狀態的變化通知,只是簡單通知到各個觀察者,告訴他們被觀察者有行動。
觀察者模式在關於目標角色、觀察者角色通信的具體實現中,有兩個版本。
一種情況便是目標角色在發生變化後,僅僅告訴觀察者角色“我變化了”,觀察者角色如果想要知道具體的變化細節,則就要自己從目標角色的接口中得到。這種模式被很形象的稱爲:拉模式——就是說變化的信息是觀察者角色主動從目標角色中“拉”出來的。
還有一種方法,那就是我目標角色“服務一條龍”,通知你發生變化的同時,通過一個參數將變化的細節傳遞到觀察者角色中去。這就是“推模式”——管你要不要,先給你啦。
這兩種模式的使用,取決於系統設計時的需要。如果目標角色比較複雜,並且觀察者角色進行更新時必須得到一些具體變化的信息,則“推模式”比較合適。如果目標角色比較簡單,則“拉模式”就很合適啦。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章