定義
- 觀察者
Observer
,也稱訂閱者Subscriber
- 被觀察者
Observable
,也稱主題Subject
定義對象間(被觀察者和觀察者)一種一對多的依賴關系,使得每當一個對象(被觀察者)改變狀態時,則所有依賴于它的對象(觀察者)都能得到通知并被自動更新。類似于發布/訂閱模式,Observer
訂閱主題,Observable
則負責發布內容,從而將二者聯系起來。
使用場景
- 用于解決解耦問題,觀察者和被觀察者高度分離,只依賴于
Observer
和Observable
抽象; - 關聯行為場景,需要注意的是,關聯行為是可拆分的,而不是“組合”關系;
- 事件多級觸發場景;
- 跨系統消息交換場景,如消息隊列,事件總線的處理機制。
Andorid源碼實例
-
ListView
適配器Adapter
的notifyDataSetChanged()
方法,在方法中遍歷所有的觀察者,回調其onChanger()
方法; -
BroadcastReceiver
的注冊與觸發,通過Context.registerReceiver()
方法將BroadcastReceiver
(相當于觀察者)注冊到AMS中,當通過sendBroadcast()
發送廣播時(相當于主題數據發生變更),所有注冊了對應IntentFilter action
的BroadcastReceiver
將會被執行; -
EventBus
消息總線 -
java.util
包中也有Observable
和Observer
的默認實現,可參考使用
UML類圖
image-20200502000759111.png
代碼示例
首先定義抽象觀察者,觀察者只關心主題的變更
public interface Observer {
/**
* 處理數據更新的方法(在主題發生變更時由主題主動觸發)
*
* @param message 變更的數據部分
*/
void update(String message);
}
接著定義抽象主題(作為被觀察者,也有命名為Observable
),主題是供觀察者觀察的對象
public interface Subject {
/**
* 訂閱操作
* @param observer 觀察者
*/
void registerObserver(Observer observer);
/**
* 取消訂閱操作
* @param observer 觀察者
*/
void removeObserver(Observer observer);
/**
* 通知變動
*/
void notifyChanged();
}
接著實現觀察者,對主題變更作具體處理
public class Subscriber implements Observer {
private String name;
private String message;
public Subscriber(String name) {
this.name = name;
}
@Override
public void update(String message) {
this.message = message;
read();
}
private void read() {
System.out.println(name + " 收到新消息: " + message);
}
}
最后再實現主題
public class Publisher implements Subject {
private String message;
private List<Observer> observerList = new ArrayList<>();
@Override
public void registerObserver(Observer observer) {
observerList.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observerList.remove(observer);
}
@Override
public void notifyChanged() {
for (Observer observer : observerList) {
observer.update(message);
}
}
public void pushMessage(String message) {
this.message = message;
System.out.println("出版社發布新消息: " + message);
// 推送消息
notifyChanged();
}
}
作如下測試:
public class Test {
public static void main(String[] args) {
Subscriber john = new Subscriber("John");
Subscriber jack = new Subscriber("jack");
Subscriber tom = new Subscriber("tom");
Publisher publisher = new Publisher();
publisher.registerObserver(john);
publisher.registerObserver(jack);
publisher.registerObserver(tom);
publisher.pushMessage("Today is Monday");
publisher.removeObserver(jack);
publisher.pushMessage("Today is Tuesday");
}
}
輸出結果如下:
出版社發布新消息: Today is Monday
John 收到新消息: Today is Monday
jack 收到新消息: Today is Monday
tom 收到新消息: Today is Monday
出版社發布新消息: Today is Tuesday
John 收到新消息: Today is Tuesday
tom 收到新消息: Today is Tuesday
優點
- 觀察者和被觀察者之間是抽象耦合,可靈活應對業務變化;
- 增強系統靈活性,可擴展性。
缺點
- 運用時需要考慮開發效率和運行效率問題,程序中包括一個被觀察者、多個觀察者、開發和調試等內容會比較復雜;
- 在Java中消息的通知默認是順序執行,一個觀察者卡頓,會影響其他觀察者的執行,所以通常情況下會采用異步的方式實現update()方法