設計模式解析:觀察者模式

WngShhng發表於2018-07-31

1、介面回撥

在學習觀察者模式之前,我們先了解一下介面回撥的概念。兩者的原理有些類似,理解了介面回撥就非常容易理解觀察者模式。

所謂介面回撥一般應用的場合是:你不知道這個方法什麼時候回返回,但是你希望在該方法結束的時候拿到方法執行的結果。常見的,比如一個方法內部開啟了執行緒,而我們希望線上程執行結束的時候拿到執行緒的執行結果。

在下面的例子中,方法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回撥出來:

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處。這近似於所謂的函式程式設計的概念,就是將介面作為一個函式注入到了方法中。

介面回撥有非常豐富的應用場景,典型的是一些非同步的場景,比如“監聽”一個按鈕的執行結果等等。

2、觀察者模式

好了,瞭解了上面的介面回撥之後,我們來看下觀察者模式。首先,我們來了解一下觀察者設計模式中的一些概念。

如果使用1中的的例子來做類比的話,那麼i就是我們的主題(Subject),我們進行介面回撥的類(將實現的Callback傳入到cal方法時所處的類)叫做觀察者(Subscriber)

觀察者模式UML

上面的是觀察者模式的UML模型。這裡的Subject介面就是主題的介面,而ConcreteSubkect是它的具體實現類,即具體的 主題。Observer介面是觀察者的介面,ConcreteObserver是具體的觀察者。一個主題往往會通過列表來維護一系列的觀察者,然後當主題發生變化的時候會便利這個列表來通知所有的觀察者。所以,這裡的Subject介面定義了三個方法,從上到下依次用於向主題中新增觀察者,從主題中移除觀察者以及通知所有的觀察者主題的更新。

下面我們給出一份最簡單的觀察者設計模式的程式碼:

1.首先是主題的定義類:

public class ConcreteSubkect 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() {
// ...
}
}複製程式碼

上面就是觀察者的基本的實現方式,這裡的實現邏輯比較簡單,但當你學習更加複雜的觀察者設計的之前理解它是很有必要的。

3、總結

觀察者與被觀察者之間是屬於輕度的關聯關係,並且是抽象耦合的,這樣,對於兩者來說都比較容易進行擴充套件。

觀察者模式是一種常用的觸發機制,它形成一條觸發鏈,依次對各個觀察者的方法進行處理。但同時,這也算是觀察者模式一個缺點,由於是鏈式觸發,當觀察者比較多的時候,效能問題是比較令人擔憂的。並且,在鏈式結構中,比較容易出現迴圈引用的錯誤,造成系統假死。並且因為觀察者列表中維護了一份觀察者的引用,當它們沒有被及時地釋放的話,可能會引起記憶體洩漏。

來源:https://juejin.im/post/5b60659df265da0f793a85ba

相關文章