觀察者模式

      觀察者模式容許多個觀察者訂閱一個主題,當主題的狀態發生變化時,可以將這種變化通知到每一個觀察者。從主題的角度看,這是典型的一對多關係,即一個主題能夠對應多個觀察者。以訂閱郵件爲例,當訂閱某一類主題內容(例如娛樂新聞,動漫等)時,若是該主題的內容有更新,那麼每個訂閱該主題的人都會受到一封內容更新的郵件,這即是典型的觀察者模式。java

      要實現郵件訂閱的功能,須要先定義一個主題接口,主題接口須要可以隨時添加或者刪除訂閱人(觀察者),而且在有內容更新時通知觀察者,其定義以下:設計模式

 1 public interface Subject {
 2   //添加觀察者
 3   void registerObserver(Observer observer);
 4 
 5   //移除觀察者
 6   void removeObserver(Observer observer);
 7 
 8   //有新內容時通知觀察者
 9   void notifyObserver();
10 }

      與主題接口對應的是觀察者接口,接口很簡單,在有內容的時候更新狀態:ide

1 public interface Observer{
2     void update();    //更新狀態
3 }

      主題接口有許多實現,這裏選擇娛樂新聞主題做爲例子:測試

 1 import java.util.ArrayList;
 2 import java.util.List;
 3 
 4 public class EntertainmentSubject implements Subject{
 5 
 6   List<Observer> observerList;
 7 
 8   public EntertainmentSubject(){
 9     this.observerList = new ArrayList<>();
10   }
11 
12   @Override
13   public void registerObserver(Observer observer) {
14     this.observerList.add(observer);
15   }
16 
17   @Override
18   public void removeObserver(Observer observer) {
19     int i = observerList.indexOf(observer);
20     if(i >= 0){
21       observerList.remove(i);
22     }
23   }
24 
25   @Override
26   public void notifyObserver() {
27     for(Observer observer : observerList){
28       observer.update();
29     }
30   }
31 
32   // 假設內容變化時會調用這個接口
33   public void contentUpdated(){
34     notifyObserver();
35   }
36 }

      主題須要在內容發生變化的時候通知全部的觀察者,這裏使用contentUpdated()方法來實現,至於主題內容變化如何調用contentUpdated()方法則不在本文的討論範圍內,這裏假設只要主題有更新就會調用這個方法。this

      接下來定義兩個具體的觀察者:spa

 1 public class ConcreteObserver1 implements Observer{
 2 
 3   Subject subject;
 4   public ConcreteObserver1(Subject subject) {
 5     this.subject = subject;
 6   }
 7 
 8   @Override
 9   public void update() {
10     System.out.println("ConcreteObserver1, 給你發個郵件,由於這裏有新內容了。。。");
11   }
12 }
 1 public class ConcreteObserver2 implements Observer{
 2 
 3   Subject subject;
 4   public ConcreteObserver2(Subject subject) {
 5     this.subject = subject;
 6   }
 7 
 8   @Override
 9   public void update() {
10     System.out.println("ConcreteObserver2, 給你發個郵件,由於這裏有新內容了。。。");
11   }
12 }

      好了,全部的類都準備就緒,是時候寫個測試來看一下觀察者模式的使用了:設計

 1 public class ObserverTest {
 2   public static void main(String[] args){
 3     EntertainmentSubject subject = new EntertainmentSubject();
 4     ConcreteObserver1 observer1 = new ConcreteObserver1(subject);
 5     ConcreteObserver2 observer2 = new ConcreteObserver2(subject);
 6     subject.registerObserver(observer1);
 7     subject.registerObserver(observer2);
 8     subject.contentUpdated();   //模擬內容更新
 9 
10     subject.removeObserver(observer1);   //observer退訂
11     subject.contentUpdated();
12   }
13 }

      輸出:code

ConcreteObserver1, 給你發個郵件,由於這裏有新內容了。。。
ConcreteObserver2, 給你發個郵件,由於這裏有新內容了。。。
ConcreteObserver2, 給你發個郵件,由於這裏有新內容了。。。

      開始的時候有兩個觀察者,內容更新的時候兩個觀察者都收到了通知,後來observer1取消了訂閱,更新的時候就再也不通知這個觀察者了。server

      固然,這裏的觀察者模式的邏輯很簡單,現實中用到的觀察者模式比這要複雜許多,不過底層的結構大致類似。並且,Java也提供了觀察者模式的相關實現Observable和Observer,使用的時候須要將Subject換成Observable,須要注意的是Observable是類而不是接口,因此若是你的類已經繼承了其餘類,就沒法使用Java的這套API了。blog

參考:

<<Head First設計模式>>

相關文章
相關標籤/搜索