觀察者模式

  • 定義

    觀察者模式定義了對(duì)象之間的一對(duì)多依賴,這樣一來(lái),當(dāng)一個(gè)對(duì)象改變狀態(tài)時(shí),他的所有依賴著都會(huì)收到通知并自動(dòng)更新.

  • 考慮這樣一個(gè)場(chǎng)景,氣象中心會(huì)隔一段時(shí)間更新一次氣象數(shù)據(jù),比如氣溫,氣壓,前端展示的頁(yè)面要能夠發(fā)現(xiàn)氣象數(shù)據(jù)更新之后就獲取到新數(shù)據(jù)并展示,比較一般的辦法就是實(shí)現(xiàn)幾個(gè)不同的類,比如展示氣溫,氣壓之類的,然后一有更新就調(diào)用每個(gè)類的更新方法來(lái)更新,這樣的辦法很不利于擴(kuò)展,比如說(shuō)我要添加一個(gè)展示相關(guān)的類,我就需要在氣象數(shù)據(jù)的相關(guān)類中做修改,這樣讓兩個(gè)類之間緊緊的關(guān)聯(lián)在一起,也就是常說(shuō)的緊耦合了,很不利于當(dāng)新需求過(guò)來(lái)時(shí)進(jìn)行擴(kuò)展;

    當(dāng)然觀察者模式就是用來(lái)解決類似的問題的,它利用一個(gè)主題來(lái)表示數(shù)據(jù)發(fā)布更新的源頭,用多個(gè)實(shí)現(xiàn)自一個(gè)接口的觀察者來(lái)負(fù)責(zé)獲取更新數(shù)據(jù)并處理的類;我們只需要針對(duì)當(dāng)前主題存儲(chǔ)它在每次更新時(shí)需要通知的觀察者信息(同一接口);在數(shù)據(jù)發(fā)生更新時(shí),只需要遍歷存儲(chǔ)的數(shù)據(jù)并調(diào)用當(dāng)前觀察者類的更新方法即可讓觀察者獲取更新數(shù)據(jù),也可以在觀察者不想獲取新數(shù)據(jù)時(shí)進(jìn)行注銷等操作,這里為什么解決了上述問題,也就是解耦合?因?yàn)槲覀儾恍枰烂總€(gè)觀察者實(shí)現(xiàn)的具體類,只需要讓他們繼承自同一接口,每次更新時(shí)調(diào)用接口的更新方法即可,具體怎么更新由每個(gè)觀察者自己來(lái)實(shí)現(xiàn).

  • UML圖


    UML圖
  • 實(shí)現(xiàn)

    主題接口:

    interface Subject{
        /**
         * 注冊(cè)觀察者
         * @param observer
         * @return
         */
        public boolean registerObserver(Observer observer);
    
        /**
         * 移除觀察者
         * @param observer
         * @return
         */
        public boolean removeObserver(Observer observer);
        int notifyObserver();
    }
    

    實(shí)際主題:

    class Subject_a implements Subject{
        // 觀察者的映射
        private Map<String ,Observer> observers = new HashMap<>();
        private String subjectName;
        // 數(shù)據(jù)
        private int a, b, c;
        Subject_a(String subjectName){
            this.subjectName = subjectName;
        }
    
        @Override
        public boolean registerObserver(Observer observer) {
            if (observers.get(observer.name()) != null){
                System.out.println(observer.name()+"已被其他觀察者占用,請(qǐng)重新注冊(cè)!");
                return false;
            }
            System.out.println(subjectName+"注冊(cè)"+observer.name());
            observers.put(observer.name(),observer);
            return true;
        }
    
        @Override
        public boolean removeObserver(Observer observer) {
            if (observers.get(observer.name()) == null){
                System.out.println("觀察者"+observer.name()+"不存在,請(qǐng)重新注銷!");
                return false;
            }
            System.out.println(subjectName+"移除"+observer.name());
            observers.remove(observer.name());
            return true;
        }
    
        /**
         * 通知觀察者
         * @return
         */
        @Override
        public int notifyObserver() {
            System.out.println(subjectName+"發(fā)布更新,更新數(shù)據(jù)為 a:"+a+" b:"+b+" c:"+c);
            for (Map.Entry<String ,Observer> entry : observers.entrySet()){
                entry.getValue().update(subjectName,a,b,c);
            }
            return observers.size();
        }
        public void dataChanged(int a, int b, int c){
            this.a = a;
            this.b = b;
            this.c = c;
            int sum = notifyObserver();
            System.out.println("接收到"+subjectName+"的人數(shù):"+sum);
        }
    }
    
    

    觀察者接口:

    interface Observer{
        /**
         * 更新數(shù)據(jù)
         * @param subjectName
         * @param a
         * @param b
         * @param c
         */
        void update(String subjectName, int a, int b, int c);
        String name();
    }
    
    

    實(shí)際觀察者:

    class ObserverA implements Observer{
    
        String observerName;
    
        public String getObserverName() {
            return observerName;
        }
    
        ObserverA(String observerName) {
            this.observerName = observerName;
        }
    
        @Override
        public void update(String subjectName,int a, int b, int c) {
            System.out.println(observerName+"收到來(lái)    自"+subjectName+"的更新,更新數(shù)據(jù)為 a:"+a+" b:"+b+" c:"+c);
        }
    
        @Override public String name() {
            return observerName;
        }
    
    }
    

    寫個(gè)代碼測(cè)試一下:

        public static void main(String[] args) {
            Subject_a subject_a = new Subject_a("主題1");
            ObserverA observerA = new ObserverA("觀察者1");
            ObserverA observerA1 = new ObserverA("觀察者2");
            subject_a.registerObserver(observerA);
            subject_a.registerObserver(observerA1);
            subject_a.dataChanged(1,2,3);
            subject_a.removeObserver(observerA);
            subject_a.dataChanged(3,4,5);
        }
    
    

    這里我們只用了一個(gè)主題,可以實(shí)現(xiàn)多個(gè)主題,來(lái)注冊(cè)不同的觀察者,只需要實(shí)現(xiàn)接口即可;我們?cè)谥黝}1上注冊(cè)了兩個(gè)觀察者1,2,并更新一次數(shù)據(jù),觀察者1,2都會(huì)接到數(shù)據(jù)并更新;接下來(lái)移除觀察者1,再更新一次數(shù)據(jù),會(huì)發(fā)現(xiàn)觀察者1接收不到新的數(shù)據(jù)了.打印一下輸出:

    輸出結(jié)果
  • 談一談優(yōu)缺點(diǎn):

    優(yōu)點(diǎn):最重要的一點(diǎn),觀察者模式將主題和觀察者解耦合,主題不需要了解觀察者內(nèi)部的實(shí)現(xiàn)即可傳輸數(shù)據(jù)過(guò)去;一對(duì)多,一個(gè)主題每次更新數(shù)據(jù)時(shí)可以傳輸給多個(gè)觀察者,觀察者想要接收更新只需要調(diào)用注冊(cè)方法,想要不接收更新只需要調(diào)用注銷方法,擴(kuò)展起來(lái)很方便.

    缺點(diǎn):由于主題不知道觀察者內(nèi)部的實(shí)現(xiàn),所以主題每次都會(huì)把所有更新的數(shù)據(jù)傳給觀察者,有可能某一觀察者只需要一點(diǎn)數(shù)據(jù)卻接受了全部,一浪費(fèi)資源,二有可能會(huì)產(chǎn)生安全相關(guān)的問題;其次每次都是主題數(shù)據(jù)更新時(shí)立馬傳給觀察者,沒有考慮有可能此時(shí)觀察者正在高負(fù)載工作,頻繁地通知觀察者會(huì)讓觀察者接收頻率太快,沒有觀察者自己想獲取數(shù)據(jù)時(shí)請(qǐng)求更新更考慮到了性能的問題.

    ?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末武契,一起剝皮案震驚了整個(gè)濱河市洽胶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌画恰,老刑警劉巖敦冬,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件没陡,死亡現(xiàn)場(chǎng)離奇詭異泡仗,居然都是意外死亡梦染,警方通過(guò)查閱死者的電腦和手機(jī)赡麦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)帕识,“玉大人泛粹,你說(shuō)我怎么就攤上這事“沽疲” “怎么了晶姊?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)伪货。 經(jīng)常有香客問我们衙,道長(zhǎng),這世上最難降的妖魔是什么碱呼? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任蒙挑,我火速辦了婚禮,結(jié)果婚禮上愚臀,老公的妹妹穿的比我還像新娘忆蚀。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布馋袜。 她就那樣靜靜地躺著男旗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪桃焕。 梳的紋絲不亂的頭發(fā)上剑肯,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音观堂,去河邊找鬼让网。 笑死,一個(gè)胖子當(dāng)著我的面吹牛师痕,可吹牛的內(nèi)容都是我干的溃睹。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼胰坟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼因篇!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起笔横,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤竞滓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后吹缔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體商佑,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年厢塘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了茶没。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡晚碾,死狀恐怖抓半,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情格嘁,我是刑警寧澤笛求,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站糕簿,受9級(jí)特大地震影響探入,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜冶伞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一新症、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧响禽,春花似錦徒爹、人聲如沸荚醒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)界阁。三九已至,卻和暖如春胖喳,著一層夾襖步出監(jiān)牢的瞬間泡躯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工丽焊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留较剃,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓技健,卻偏偏與公主長(zhǎng)得像写穴,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子雌贱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 1 場(chǎng)景問題# 1.1 訂閱報(bào)紙的過(guò)程## 來(lái)考慮實(shí)際生活中訂閱報(bào)紙的過(guò)程啊送,這里簡(jiǎn)單總結(jié)了一下,訂閱報(bào)紙的基本流程...
    七寸知架構(gòu)閱讀 4,597評(píng)論 5 57
  • 觀察者模式定義了一種一對(duì)多的依賴關(guān)系欣孤,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象馋没。這個(gè)主題對(duì)象在狀態(tài)上發(fā)生變化時(shí),會(huì)通...
    扈扈哈嘿閱讀 1,316評(píng)論 0 12
  • 客戶需求 程序設(shè)計(jì) 一個(gè)氣象站對(duì)應(yīng)著多個(gè)客戶端降传,氣象站的數(shù)據(jù)一發(fā)生變化篷朵,客戶端的數(shù)據(jù)也要隨著更新,這就形成了一種依...
    BlainPeng閱讀 992評(píng)論 1 17
  • 1. 概述 有時(shí)被稱作發(fā)布/訂閱模式搬瑰,觀察者模式定義了一種一對(duì)多的依賴關(guān)系款票,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象...
    eb51589b1211閱讀 384評(píng)論 0 0
  • 《水滸傳》里108條好漢都秉行忠和義控硼,他們有血有肉泽论,性格鮮活,可歌可泣卡乾。然而我最欣賞的是孝義黑三郎翼悴、及時(shí)雨、呼保義...
    謝紫洋閱讀 328評(píng)論 0 3