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