觀察者模式

觀察者模式介紹

觀察者模式是日常使用比較廣泛的一種模式,它可以很有效的解耦,將被觀察者和觀察者解耦,使他們之間的依賴性更小。

觀察者模式定義

它定義了一種一對多的依賴關(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í)行效率,這種情況一般考慮采用異步的方式。

?
?
?

參考資料

原文地址:http://www.itdecent.cn/p/75a1b72d487a

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容