觀察者模式介紹
觀察者模式是日常使用比較廣泛的一種模式,它可以很有效的解耦,將被觀察者和觀察者解耦,使他們之間的依賴性更小。
觀察者模式定義
它定義了一種一對多的依賴關(guān)系,讓多個觀察者對象同時監(jiān)聽某一個被觀察者對象。這個被觀察者對象在狀態(tài)變化時,會通知所有的觀察者對象,使他們能夠自動更新自己。
比如我們當(dāng)年在學(xué)校訂閱的仁愛英語報,仁愛英語報的報社就相當(dāng)于被觀察者,而我們向報社訂閱了報紙,我們就相當(dāng)于了觀察者。這個時候只要仁愛英語報有更新,就會有新的報紙內(nèi)容更新到我們每個觀察者的手中。如果過了一段時間,張三發(fā)現(xiàn)自己不適合學(xué)英語,就向報社取消了訂閱,這時他就不屬于觀察者,當(dāng)有新的報紙內(nèi)容更新,就不會更新到他手里。如下圖:

觀察者使用場景
- 一個對象狀態(tài)的更新,需要其他對象同步更新,而且其他對象的數(shù)量動態(tài)可變。
觀察者UML類圖

UML類圖
- Subject:抽象主題,也就是我們上文的被觀察者(Observable),被觀察者提供兩個接口,可以增加和刪除觀察者對象。每個被觀察者都可以添加任意數(shù)量的觀察者。
- ConcreteSubject:具體主題(具體的被觀察者),實現(xiàn)自Subiect,該角色將訂閱的觀察者保存到一個集合當(dāng)中,當(dāng)具體的被觀察者內(nèi)部狀態(tài)發(fā)生改變時,給所有訂閱的觀察者發(fā)送更新通知。
- Observer:觀察者接口,所有的觀察者都實現(xiàn)此觀察者接口,此接口定義了一個update方法,在得到主題的通知時更新自己。
- ConcreteObserver:具體的觀察者,實現(xiàn)了觀察者接口,以便被觀察者狀態(tài)改變時,可以及時更新自己狀態(tài)。
觀察者的簡單實現(xiàn)
觀察者接口(Observer)
public interface Observer {
void updata(String msg);
}
具體觀察者(ConcreteObserver)
public class LiSi implements Observer {
private ObServerAble obServerAble;
public LiSi(ObServerAble obServerAble) {
this.obServerAble = obServerAble;
obServerAble.registObserver(this);
}
@Override
public void updata(String msg) {
System.out.println("LiSi updata = " + msg);
}
}
被觀察者接口(Observable)
public interface ObServerAble {
void registObserver(Observer observer);
void unRegistObserver(Observer observer);
//通知所有觀察者
void notifiAll();
}
具體被觀察者(ConcreteSubject)
public class RenAiNewspaper implements ObServerAble {
private List<Observer> list;
private String message;
public RenAiNewspaper() {
list = new ArrayList<>();
}
@Override
public void registObserver(Observer observer) {
list.add(observer);
}
@Override
public void unRegistObserver(Observer observer) {
int i = list.indexOf(observer);
if ( i >= 0){
list.remove(i);
}
}
@Override
public void notifiAll() {
for (int i = 0; i < list.size(); i++){
Observer observer = list.get(i);
observer.updata(message);
}
}
//當(dāng)值改變調(diào)用
public void MessageUpdate(){
notifiAll();
}
//寫入更新內(nèi)容
public void setMessage(String str){
this.message = str;
MessageUpdate();
}
}
測試代碼
public class MainTest {
public static void main(String[] args) {
RenAiNewspaper renAiNewspaper = new RenAiNewspaper();
Observer lisiObserver = new LiSi(renAiNewspaper);
Observer wangErMaObserver = new WangErMa(renAiNewspaper);
renAiNewspaper.setMessage("仁愛英語報,第一期內(nèi)容");
}
}
-------------------------------------------------------
Output:
LiSi updata = 仁愛英語報,第一期內(nèi)容
WangErMa updata = 仁愛英語報,第一期內(nèi)容
可以看到結(jié)果,LiSI和WangErMa都收到了仁愛英語報的更新。這樣就完成了一對多的通知功能。因為整個系統(tǒng)都是依賴ObServerAble和Observer這兩個接口,所以RenAiNewspaper和LiSi完全沒有耦合,就算后期有新的觀察者想訂閱消息,只要實現(xiàn)Observer即可,被觀察者部分不需要修改代碼。
觀察者模式的優(yōu)缺點
優(yōu)點
- 解耦,雙方都依賴接口編程。
- 增強(qiáng)程序的靈活性,可擴(kuò)展性。
缺點
- 如果一個被觀察者有很多觀察者,將所有觀察者都通知到需要花費(fèi)很多時間。
- java代碼是順序執(zhí)行,一個觀察者卡頓,會影響整體的執(zhí)行效率,這種情況一般考慮采用異步的方式。
?
?
?
參考資料
- Android源碼設(shè)計模式
- Head First 設(shè)計模式
-
https://www.cnblogs.com/pjl1119/p/9727444.html
?