在學習觀察者模式以前,咱們先了解一下接口回調的概念。二者的原理有些相似,理解了接口回調就很是容易理解觀察者模式。java
所謂接口回調通常應用的場合是:你不知道這個方法何時回返回,可是你但願在該方法結束的時候拿到方法執行的結果。常見的,好比一個方法內部開啓了線程,而咱們但願在線程執行結束的時候拿到線程的執行結果。編程
在下面的例子中,方法 cal()
定義了一個局部變量 i,隨後開啓了一個線程,並在線程執行的時候修改了 i 的值。咱們但願在線程執行完畢的時候達到 i 的執行結果。設計模式
public int cal() {
int i;
new Thread(new Runnable() {
Thread.sleep(3000); // throw ... ignore it
i++;
}).start();
return i;
}
複製代碼
使用 return 確定不行,由於方法結束時,線程可能尚未結束,那麼 return 返回的結果是沒法被預料到的,多是線程執行完畢以後的,也多是沒有被線程修改就返回了的。異步
咱們可使用接口回調解決這個問題。咱們能夠在調用該方法的時候傳入一個接口 Callback 的實例。在線程中執行完全部的邏輯以後,咱們使用該接口的 call()
方法將 i 回調出來:ide
public void cal(Callback callback) {
int i;
new Thread(new Runnable() {
Thread.sleep(3000); // throw ... ignore it
i++;
if (callback != null) {
callback.call(i); // 1
}
}).start();
}
複製代碼
固然,接口回調更像是將個人 call()
方法注入到了上述代碼中的 1 處。這近似於所謂的函數編程的概念,就是將接口做爲一個函數注入到了方法中。函數
接口回調有很是豐富的應用場景,典型的是一些異步的場景,好比 「監聽」 一個按鈕的執行結果等等。性能
好了,瞭解了上面的接口回調以後,咱們來看下觀察者模式。首先,咱們來了解一下觀察者設計模式中的一些概念。學習
若是使用 1 中的的例子來作類比的話,那麼 i 就是咱們的主題(Subject),咱們進行接口回調的類(將實現的 Callback 傳入到 cal 方法時所處的類)叫作觀察者(Subscriber)。this
上面的是觀察者模式的UML模型。這裏的 Subject
接口就是主題的接口,而 ConcreteSubkect
是它的具體實現類,即具體的 主題。Observer
接口是觀察者的接口,ConcreteObserver
是具體的觀察者。一個主題每每會經過列表來維護一系列的觀察者,而後當主題發生變化的時候會便利這個列表來通知全部的觀察者。因此,這裏的 Subject
接口定義了三個方法,從上到下依次用於向主題中添加觀察者,從主題中移除觀察者以及通知全部的觀察者主題的更新。spa
下面咱們給出一份最簡單的觀察者設計模式的代碼:
1.首先是主題的定義類:
public class ConcreteSubject implements Subject {
// 經過隊列維護觀察者列表
private List<Observer> observers = new LinkedList<>();
// 註冊一個觀察者
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
// 移除一個觀察者
@Override
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
if (i >= 0) {
observers.remove(o);
}
}
// 通知全部觀察者主題的更新
@Override
public void notifyObservers() {
for (Observer o : observers) {
o.method();
}
}
}
複製代碼
2.接下來是觀察者的定義類:
public class ConcreteObserver implements Observer {
// 該觀察者訂閱的主題
private Subject subject;
public ConcreteObserver(Subject subject) {
this.subject = subject;
// 將當前觀察者添加到主題訂閱列表中
subject.registerObserver(this);
}
// 當主題發生變化的時候,主題會遍歷觀察者列表並經過調用該方法來通知觀察者
@Override
public void method() {
// ...
}
}
複製代碼
上面就是觀察者的基本的實現方式,這裏的實現邏輯比較簡單,但當你學習更加複雜的觀察者設計的以前理解它是頗有必要的。
觀察者與被觀察者之間是屬於輕度的關聯關係,而且是抽象耦合的,這樣,對於二者來講都比較容易進行擴展。
觀察者模式是一種經常使用的觸發機制,它造成一條觸發鏈,依次對各個觀察者的方法進行處理。但同時,這也算是觀察者模式一個缺點,因爲是鏈式觸發,當觀察者比較多的時候,性能問題是比較使人擔心的。而且,在鏈式結構中,比較容易出現循環引用的錯誤,形成系統假死。而且由於觀察者列表中維護了一份觀察者的引用,當它們沒有被及時地釋放的話,可能會引發內存泄漏。