公號:碼農充電站pro
主頁:https://codeshellme.github.iohtml
觀察者模式(Observer Design Pattern)也被稱爲發佈訂閱模式(Publish-Subscribe Design Pattern),主要用於更好的解決向對象通知消息的問題。java
觀察者模式定義了對象之間的一對多依賴,當對象狀態改變的時候,全部依賴者都會自動收到通知。git
觀察者模式能夠用不少稱呼來描述,好比:github
咱們以訂閱報紙爲例,來描述 Subject 與 Observer 之間的關係。redis
Subject 至關於報社,Observer 就至關於訂閱報紙的用戶:算法
Subject 與 Observer 是一對多關係:shell
這裏直接給出觀察者模式的類圖,這是最經典的實現方式,其它的變種均可以在它的基礎上加以改進。apache
從類圖中能夠知道,Subject 是一個接口,有三個抽象方法:設計模式
registerObserver
:用於註冊 observer。removeObserver
:用於移除 observer。notifyObservers
:當有了消息,通知全部 observers。Observer 也是一個接口,有一個抽象方法:框架
update
:當 subject 發來新消息時,用於更新消息。下面咱們來用代碼實現觀察者模式。
首先是兩個接口 Subject 與 Observer:
interface Subject { void registerObserver(Observer o); void removeObserver(Observer o); void notifyObservers(String info); } interface Observer { void update(String info); }
這兩個接口徹底是按照類圖中的內容來實現的,其中變量 info
的類型能夠根據實際的應用場景來定。
再實現 ConcreteSubject 和 ConcreteObserver :
class ConcreteSubject implements Subject { // 用於存放 observer private final ArrayList<Observer> observers; public ConcreteSubject() { observers = new ArrayList(); } public void registerObserver(Observer o) { observers.add(o); } public void removeObserver(Observer o) { observers.remove(o); } public void notifyObservers(String info) { for (Observer o: observers) { o.update(info); } } } class ConcreteObserver implements Observer { private final String name; public ConcreteObserver(String name) { this.name = name; } public void update(String info) { System.out.println(this.name + " get info: " + info); } }
ConcreteSubject
中的 observers
用於存儲觀察者,這裏使用的類型是 ArrayList
,也能夠根據實際的應用場景來選擇。
ConcreteObserver
中的 name
只是爲了表示不一樣的觀察者,觀察者在收到消息後,將消息打印在控制檯。
測試這兩個類:
// 建立被觀察者 ConcreteSubject s = new ConcreteSubject(); // 建立兩個觀察者 ConcreteObserver o1 = new ConcreteObserver("o1"); ConcreteObserver o2 = new ConcreteObserver("o2"); // 註冊觀察者 s.registerObserver(o1); // 註冊 o1 s.registerObserver(o2); // 註冊 o2 s.notifyObservers("info1"); // 向觀察者通知消息 System.out.println("remove observer o1"); s.removeObserver(o1); // 移除 o1 s.notifyObservers("info2"); // 再向觀察者通知消息
輸出以下:
o1 get info: info1 o2 get info: info1 remove observer o1 o2 get info: info2
能夠看到,第一次通知消息時,o1 和 o2 都收到消息了,在移除 o1 以後再發送消息,只有 o2 能收到消息。
這就是觀察者模式最簡潔的一種實現方式,很是簡單。我把完整的代碼放在了這裏。
根據不一樣的應用場景和需求,觀察者模式能夠有不一樣的實現方式,好比下面幾種:
同步阻塞方式
根據這種劃分方式,上面咱們實現的就是同步阻塞的方式,當有新消息的時候,Subject
會將消息 notify
給全部的 Observer
,直到全部的 Observer
執行完畢它的 update
過程,整個通知過程纔算完畢,這整個過程是一個阻塞的過程。
異步非阻塞方式
爲了加快整個 notify
過程,咱們能夠將同步阻塞的方式改成異步非阻塞的方式。
一種簡單的實現就是使用線程,就是在 update
方法中使用線程來完成任務,以下:
public void update(String info) { Thread t = new Thread(new Runnable() { public void run() { // 處理任務 } }); t.start(); }
Google Guava EventBusExplained 是一個通用的觀察者模式框架,你能夠去了解一下。
跨進程方式
同步阻塞與異步非阻塞都屬於進程以內的實現,對於跨進程的實現,通常都是基於消息隊列來實現。至於這方面的應用,有不少現成的,成熟的組件可使用,好比:
觀察者模式旨在將觀察者與被觀察者解耦,在不少地方都用到了該模式,好比 Swing,JavaBeans 等。
觀察者模式最經典的實現方式很簡單,在實際應用中,能夠在其基礎上進行改進。
(本節完。)
推薦閱讀:
歡迎關注做者公衆號,獲取更多技術乾貨。