原文:設計模式(五)觀察者模式html
觀察者模式(又被稱爲發佈-訂閱(Publish/Subscribe)模式,屬於行爲型模式的一種,它定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態變化時,會通知全部的觀察者對象,使他們可以自動更新本身。java
在觀察者模式中有以下角色:設計模式
Subject:抽象主題(抽象被觀察者),抽象主題角色把全部觀察者對象保存在一個集合裏,每一個主題均可以有任意數量的觀察者,抽象主題提供一個接口,能夠增長和刪除觀察者對象。微信
ConcreteSubject:具體主題(具體被觀察者),該角色將有關狀態存入具體觀察者對象,在具體主題的內部狀態發生改變時,給全部註冊過的觀察者發送通知。異步
Observer:抽象觀察者,是觀察者者的抽象類,它定義了一個更新接口,使得在獲得主題更改通知時更新本身。ide
ConcrereObserver:具體觀察者,實現抽象觀察者定義的更新接口,以便在獲得主題更改通知時更新自身的狀態。this
觀察者模式這種發佈-訂閱的形式咱們能夠拿微信公衆號來舉例,假設微信用戶就是觀察者,微信公衆號是被觀察者,有多個的微信用戶關注了程序猿這個公衆號,當這個公衆號更新時就會通知這些訂閱的微信用戶。好了咱們來看看用代碼如何實現:.net
抽象觀察者(Observer)設計
裏面定義了一個更新的方法:調試
public interface Observer { public void update(String message); }
具體觀察者(ConcrereObserver)
微信用戶是觀察者,裏面實現了更新的方法:
public class WeixinUser implements Observer { // 微信用戶名 private String name; public WeixinUser(String name) { this.name = name; } @Override public void update(String message) { System.out.println(name + "-" + message); } }
抽象被觀察者(Subject)
抽象主題,提供了attach、detach、notify三個方法:
public interface Subject { /** * 增長訂閱者 * @param observer */ public void attach(Observer observer); /** * 刪除訂閱者 * @param observer */ public void detach(Observer observer); /** * 通知訂閱者更新消息 */ public void notify(String message); }
具體被觀察者(ConcreteSubject)
微信公衆號是具體主題(具體被觀察者),裏面存儲了訂閱該公衆號的微信用戶,並實現了抽象主題中的方法:
public class SubscriptionSubject implements Subject { //儲存訂閱公衆號的微信用戶 private List<Observer> weixinUserlist = new ArrayList<Observer>(); @Override public void attach(Observer observer) { weixinUserlist.add(observer); } @Override public void detach(Observer observer) { weixinUserlist.remove(observer); } @Override public void notify(String message) { for (Observer observer : weixinUserlist) { observer.update(message); } } }
客戶端調用
public class Client { public static void main(String[] args) { SubscriptionSubject mSubscriptionSubject=new SubscriptionSubject(); //建立微信用戶 WeixinUser user1=new WeixinUser("楊影楓"); WeixinUser user2=new WeixinUser("月眉兒"); WeixinUser user3=new WeixinUser("紫軒"); //訂閱公衆號 mSubscriptionSubject.attach(user1); mSubscriptionSubject.attach(user2); mSubscriptionSubject.attach(user3); //公衆號更新發出消息給訂閱的微信用戶 mSubscriptionSubject.notify("劉望舒的專欄更新了"); } }
結果
楊影楓-劉望舒的專欄更新了 月眉兒-劉望舒的專欄更新了 紫軒-劉望舒的專欄更新了
一、關聯行爲場景,須要注意的是,關聯行爲是可拆分的,而不是「組合」關係。
二、事件多級觸發場景。
三、跨系統的消息交換場景,如消息隊列、事件總線的處理機制。
四、有多個子類共有的方法,且邏輯相同。
五、重要的、複雜的方法,能夠考慮做爲模板方法。
一、解除耦合,讓耦合的雙方都依賴於抽象,觀察者和被觀察者是抽象耦合的,從而使得各自的變換都不會影響另外一邊的變換。
二、創建一套觸發機制。
一、若是一個被觀察者對象有不少的直接和間接的觀察者的話,將全部的觀察者都通知到會花費不少時間。
二、若是在觀察者和觀察目標之間有循環依賴的話,觀察目標會觸發它們之間進行循環調用,可能致使系統崩潰。
三、觀察者模式沒有相應的機制讓觀察者知道所觀察的目標對象是怎麼發生變化的,而僅僅只是知道觀察目標發生了變化。
四、在應用觀察者模式時須要考慮一下開發效率和運行效率的問題,程序中包括一個被觀察者、多個觀察者,開發、調試等內容會比較複雜,並且在Java中消息的通知通常是順序執行,那麼一個觀察者卡頓,會影響總體的執行效率,在這種狀況下,通常會採用異步實現。
參考資料:
觀察者模式