觀察者通常能夠看作是第三者,好比在學校上自習的時候,你們確定都有過交頭接耳、各類玩耍的經歷,這時總會有一個「放風」的小夥伴,當老師即將出現時及時「通知」你們老師來了。再好比,拍賣會的時候,你們相互叫價,拍賣師會觀察最高標價,而後通知給其它競價者競價,這就是一個觀察者模式。git
對於觀察者模式而言,確定有觀察者和被觀察者之分。好比在一個目錄下創建一個文件,這時系統會通知目錄管理器增長目錄,並通知磁盤減小空間,在這裏,文件就是觀察者,目錄管理器和磁盤就是被觀察者。數組
觀察者模式(Observer),又叫發佈-訂閱模式(Publish/Subscribe),定義對象間一種一對多的依賴關係,使得每當一個對象改變狀態,則全部依賴於它的對象都會獲得通知並自動更新。UML結構圖以下:安全
其中,Subject類是主題,它把全部對觀察者對象的引用文件存在了一個彙集裏,每一個主題均可以有任何數量的觀察者。抽象主題提供了一個接口,能夠增長和刪除觀察者對象;Observer類是抽象觀察者,爲全部的具體觀察者定義一個接口,在獲得主題的通知時更新本身;ConcreteSubject類是具體主題,將有關狀態存入具體觀察者對象,在具體主題內部狀態改變時,給全部登記過的觀察者發出通知;ConcreteObserver是具體觀察者,實現抽象觀察者角色所要求的更新接口,以便使自己的狀態與主題的狀態相協同。異步
首先定義一個觀察者數組,並實現增、刪及通知操做。它的職責很簡單,就是定義誰能觀察,誰不能觀察,用Vector是線程同步的,比較安全,也可使用ArrayList,是線程異步的,但不安全。ide
1 public class Subject { 2 3 //觀察者數組 4 private Vector<Observer> oVector = new Vector<>(); 5 6 //增長一個觀察者 7 public void addObserver(Observer observer) { 8 this.oVector.add(observer); 9 } 10 11 //刪除一個觀察者 12 public void deleteObserver(Observer observer) { 13 this.oVector.remove(observer); 14 } 15 16 //通知全部觀察者 17 public void notifyObserver() { 18 for(Observer observer : this.oVector) { 19 observer.update(); 20 } 21 } 22 23 }
觀察者通常是一個接口,每個實現該接口的實現類都是具體觀察者。測試
1 public interface Observer { 2 //更新 3 public void update(); 4 }
繼承Subject類,在這裏實現具體業務,在具體項目中,該類會有不少變種。this
1 public class ConcreteSubject extends Subject { 2 3 //具體業務 4 public void doSomething() { 5 //... 6 super.notifyObserver(); 7 } 8 9 }
實現Observer接口。spa
1 public class ConcreteObserver implements Observer { 2 3 @Override 4 public void update() { 5 System.out.println("收到消息,進行處理"); 6 } 7 8 }
首先建立一個被觀察者,而後定義一個觀察者,將該被觀察者添加到該觀察者的觀察者數組中,進行測試。線程
1 public class Client { 2 3 public static void main(String[] args) { 4 //建立一個主題 5 ConcreteSubject subject = new ConcreteSubject(); 6 //定義一個觀察者 7 Observer observer = new ConcreteObserver(); 8 //觀察 9 subject.addObserver(observer); 10 //開始活動 11 subject.doSomething(); 12 } 13 14 }
運行結果以下:code
下面舉一個具體實例,假設上班時間有一部分同事在看股票,一部分同事在看NBA,這時老闆回來了,前臺通知了部分同事老闆回來了,這些同事及時關閉了網頁沒被發現,而沒被通知到的同事被抓了個現行,被老闆親自「通知」關閉網頁,UML圖以下:
1 public interface Subject { 2 3 //增長 4 public void attach(Observer observer); 5 //刪除 6 public void detach(Observer observer); 7 //通知 8 public void notifyObservers(); 9 10 //狀態 11 public void setAction(String action); 12 public String getAction(); 13 14 }
1 public abstract class Observer { 2 3 protected String name; 4 protected Subject subject; 5 6 public Observer(String name, Subject subject) { 7 this.name = name; 8 this.subject = subject; 9 } 10 11 public abstract void update(); 12 13 }
前臺Secretary和老闆Boss做爲具體通知者,實現Subject接口。這裏只給出Secretary類的代碼,Boss類與之相似。
1 public class Secretary implements Subject { 2 3 //同事列表 4 private List<Observer> observers = new LinkedList<>(); 5 private String action; 6 7 //添加 8 @Override 9 public void attach(Observer observer) { 10 observers.add(observer); 11 } 12 13 //刪除 14 @Override 15 public void detach(Observer observer) { 16 observers.remove(observer); 17 } 18 19 //通知 20 @Override 21 public void notifyObservers() { 22 for(Observer observer : observers) { 23 observer.update(); 24 } 25 } 26 27 //前臺狀態 28 @Override 29 public String getAction() { 30 return action; 31 } 32 33 @Override 34 public void setAction(String action) { 35 this.action = action; 36 } 37 38 }
StockObserver是看股票的同事,NBAObserver是看NBA的同事,做爲具體觀察者,繼承Observer類。這裏只給出StockObserver類的代碼,NBAObserver類與之相似。
1 public class StockObserver extends Observer { 2 3 public StockObserver(String name, Subject subject) { 4 super(name, subject); 5 } 6 7 @Override 8 public void update() { 9 System.out.println(subject.getAction() + "\n" + name + "關閉股票行情,繼續工做"); 10 } 11 12 }
前臺做爲通知者,通知觀察者。這裏添加adam和tom到通知列表,並從通知列表中刪除了adam,測試沒在通知列表中的對象不會收到通知。
1 public class Client { 2 3 public static void main(String[] args) { 4 //前臺爲通知者 5 Secretary secretary = new Secretary(); 6 7 StockObserver observer = new StockObserver("adam", secretary); 8 NBAObserver observer2 = new NBAObserver("tom", secretary); 9 10 //前臺通知 11 secretary.attach(observer); 12 secretary.attach(observer2); 13 14 //adam沒被前臺通知到,因此被老闆抓了個現行 15 secretary.detach(observer); 16 17 //老闆回來了 18 secretary.setAction("當心!Boss回來了!"); 19 //發通知 20 secretary.notifyObservers(); 21 } 22 23 }
運行結果以下,只有tom接收到了通知:
老闆做爲通知者,通知觀察者。這裏將tom從老闆的通知列表中移除,老闆只通知到了adam。
1 public class Client { 2 3 public static void main(String[] args) { 4 //老闆爲通知者 5 Boss boss = new Boss(); 6 7 StockObserver observer = new StockObserver("adam", boss); 8 NBAObserver observer2 = new NBAObserver("tom", boss); 9 10 //老闆通知 11 boss.attach(observer); 12 boss.attach(observer2); 13 14 //tom沒被老闆通知到,因此不用捱罵 15 boss.detach(observer2); 16 17 //老闆回來了 18 boss.setAction("咳咳,我大Boss回來了!"); 19 //發通知 20 boss.notifyObservers(); 21 } 22 23 }
運行結果以下,只有adam捱罵了:
當一個對象的改變須要同時改變其它對象,而且它不知道具體有多少對象有待改變的時候,應該考慮使用觀察者模式。
而使用觀察者模式的動機在於:將一個系統分割成一系列相互協做的類有一個很很差的反作用,就是須要維護相關對象間的一致性,咱們不但願爲了維持一致性而使各種緊密耦合,這樣會給維護、擴展和重用都帶來不便,而觀察者模式所作的工做就是在解除耦合。