定義
- 觀察者
Observer,也稱訂閱者Subscriber - 被觀察者
Observable,也稱主題Subject
定義對象間(被觀察者和觀察者)一種一對多的依賴關(guān)系,使得每當(dāng)一個對象(被觀察者)改變狀態(tài)時,則所有依賴于它的對象(觀察者)都能得到通知并被自動更新。類似于發(fā)布/訂閱模式,Observer訂閱主題,Observable則負(fù)責(zé)發(fā)布內(nèi)容,從而將二者聯(lián)系起來。
使用場景
- 用于解決解耦問題,觀察者和被觀察者高度分離,只依賴于
Observer和Observable抽象; - 關(guān)聯(lián)行為場景,需要注意的是,關(guān)聯(lián)行為是可拆分的,而不是“組合”關(guān)系;
- 事件多級觸發(fā)場景;
- 跨系統(tǒng)消息交換場景,如消息隊列,事件總線的處理機制。
Andorid源碼實例
-
ListView適配器Adapter的notifyDataSetChanged()方法,在方法中遍歷所有的觀察者,回調(diào)其onChanger()方法; -
BroadcastReceiver的注冊與觸發(fā),通過Context.registerReceiver()方法將BroadcastReceiver(相當(dāng)于觀察者)注冊到AMS中,當(dāng)通過sendBroadcast()發(fā)送廣播時(相當(dāng)于主題數(shù)據(jù)發(fā)生變更),所有注冊了對應(yīng)IntentFilter action的BroadcastReceiver將會被執(zhí)行; -
EventBus消息總線 -
java.util包中也有Observable和Observer的默認(rèn)實現(xiàn),可參考使用
UML類圖

image-20200502000759111.png
代碼示例
首先定義抽象觀察者,觀察者只關(guān)心主題的變更
public interface Observer {
/**
* 處理數(shù)據(jù)更新的方法(在主題發(fā)生變更時由主題主動觸發(fā))
*
* @param message 變更的數(shù)據(jù)部分
*/
void update(String message);
}
接著定義抽象主題(作為被觀察者,也有命名為Observable),主題是供觀察者觀察的對象
public interface Subject {
/**
* 訂閱操作
* @param observer 觀察者
*/
void registerObserver(Observer observer);
/**
* 取消訂閱操作
* @param observer 觀察者
*/
void removeObserver(Observer observer);
/**
* 通知變動
*/
void notifyChanged();
}
接著實現(xiàn)觀察者,對主題變更作具體處理
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);
}
}
最后再實現(xiàn)主題
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("出版社發(fā)布新消息: " + 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");
}
}
輸出結(jié)果如下:
出版社發(fā)布新消息: Today is Monday
John 收到新消息: Today is Monday
jack 收到新消息: Today is Monday
tom 收到新消息: Today is Monday
出版社發(fā)布新消息: Today is Tuesday
John 收到新消息: Today is Tuesday
tom 收到新消息: Today is Tuesday
優(yōu)點
- 觀察者和被觀察者之間是抽象耦合,可靈活應(yīng)對業(yè)務(wù)變化;
- 增強系統(tǒng)靈活性,可擴展性。
缺點
- 運用時需要考慮開發(fā)效率和運行效率問題,程序中包括一個被觀察者、多個觀察者、開發(fā)和調(diào)試等內(nèi)容會比較復(fù)雜;
- 在Java中消息的通知默認(rèn)是順序執(zhí)行,一個觀察者卡頓,會影響其他觀察者的執(zhí)行,所以通常情況下會采用異步的方式實現(xiàn)update()方法