14拜秧、觀察者模式(Observer Pattern)

1. 觀察者模式

1.1 簡(jiǎn)介

??觀察者(Observer)模式的定義:指多個(gè)對(duì)象間存在一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí)枉氮,所有依賴于它的對(duì)象都得到通知并被自動(dòng)更新暖庄。這種模式有時(shí)又稱作發(fā)布-訂閱模式、模型-視圖模式惹悄,它是對(duì)象行為型模式肩钠。

??Observer并非主動(dòng)觀察暂殖,而是被動(dòng)觀察当纱。觀察者模式可以理解為發(fā)布-訂閱模式,即多個(gè)訂閱者(觀察者)向發(fā)布者(被觀察者)訂閱狀態(tài)信息莉给,當(dāng)發(fā)布者更新?tīng)顟B(tài)時(shí)會(huì)將狀態(tài)信息向它的訂閱者發(fā)布信息廉沮。發(fā)布者需要自己維護(hù)訂閱者列表,可以注冊(cè)或者注銷(xiāo)對(duì)狀態(tài)信息感興趣或不感興趣的訂閱者叁幢。

1.2 Observer模式結(jié)構(gòu)

模式結(jié)構(gòu):

觀察者模式uml.gif

模式角色:

  • 抽象主題(Subject)角色:也叫抽象目標(biāo)類坪稽,它提供了一個(gè)用于保存觀察者對(duì)象的聚集類和增加、刪除觀察者對(duì)象的方法黍判,以及通知所有觀察者的抽象方法篙梢。
  • 具體主題(Concrete Subject)角色:也叫具體目標(biāo)類,它實(shí)現(xiàn)抽象目標(biāo)中的通知方法渤滞,當(dāng)具體主題的內(nèi)部狀態(tài)發(fā)生改變時(shí),通知所有注冊(cè)過(guò)的觀察者對(duì)象陶舞。
  • 抽象觀察者(Observer)角色:它是一個(gè)抽象類或接口绪励,它包含了一個(gè)更新自己的抽象方法,當(dāng)接到具體主題的更改通知時(shí)被調(diào)用停做。
  • 具體觀察者(Concrete Observer)角色:實(shí)現(xiàn)抽象觀察者中定義的抽象方法蠢护,以便在得到目標(biāo)的更改通知時(shí)更新自身的狀態(tài)养涮。

2. Observer模式示例

??我們模擬一個(gè)學(xué)校上下課鈴聲的事件處理過(guò)程眉抬,老師和學(xué)生聽(tīng)到上課鈴聲準(zhǔn)備上課懈凹,聽(tīng)到下課鈴聲準(zhǔn)備下課。學(xué)校的“鈴”是事件源和目標(biāo)库北,“老師”和“學(xué)生”是事件監(jiān)聽(tīng)器和具體觀察者,“鈴聲”是事件類寒瓦。

鈴聲事件處理程序uml:

鈴聲事件處理程序uml.gif

鈴聲事件類:

public class RingEvent
{   
    private boolean sound;    //true表示上課鈴聲,false表示下課鈴聲
    public RingEvent(boolean sound)
    {
        this.sound=sound;
    }   
    public void setSound(boolean sound)
    {
        this.sound=sound;
    }
    public boolean getSound()
    {
        return this.sound;
    }
}

鈴聲目標(biāo)類:

public class BellEventSource
{    
    private List<BellEventListener> listener; 
    public BellEventSource()
    { 
        listener=new ArrayList<BellEventListener>();        
    }
    //給事件源綁定監(jiān)聽(tīng)器 
    public void addPersonListener(BellEventListener ren)
    { 
        listener.add(ren); 
    }
    //事件觸發(fā)器:敲鐘杂腰,當(dāng)鈴聲sound的值發(fā)生變化時(shí)椅文,觸發(fā)事件。
    public void ring(boolean sound)
    {
        String type=sound?"上課鈴":"下課鈴";
        System.out.println(type+"響少辣!");
        RingEvent event=new RingEvent(sound);     
        notifies(event);    //通知注冊(cè)在該事件源上的所有監(jiān)聽(tīng)器                
    }   
    //當(dāng)事件發(fā)生時(shí),通知綁定在該事件源上的所有監(jiān)聽(tīng)器做出反應(yīng)(調(diào)用事件處理方法)
    protected void notifies(RingEvent e)
    { 
        BellEventListener ren=null; 
        Iterator<BellEventListener> iterator=listener.iterator(); 
        while(iterator.hasNext())
        { 
            ren=iterator.next(); 
            ren.heardBell(e); 
        } 
    }
}

觀察者接口:

interface  BellEventListener extends EventListener
{
    //事件處理方法羡蛾,聽(tīng)到鈴聲
    public void heardBell(RingEvent e);
}

監(jiān)聽(tīng)者老師:

public class TeachEventListener implements BellEventListener
{
    public void heardBell(RingEvent e)
    {        
        if(e.getSound())
        {
            System.out.println("老師開(kāi)始上課...");           
        }
        else
        {
            System.out.println("老師下課...");   
        }          
    }
}

監(jiān)聽(tīng)者學(xué)生:

public class StuEventListener implements BellEventListener
{
    public void heardBell(RingEvent e)
    {        
        if(e.getSound())
        {
            System.out.println("同學(xué)們,上課了...");           
        }
        else
        {
            System.out.println("同學(xué)們林说,下課了...");   
        }          
    }
}

客戶端調(diào)用:

    public static void main(String[] args)
    {
        BellEventSource bell=new BellEventSource();     
        bell.addPersonListener(new TeachEventListener()); //注冊(cè)監(jiān)聽(tīng)器(老師)
        bell.addPersonListener(new StuEventListener());    //注冊(cè)監(jiān)聽(tīng)器(學(xué)生)
        bell.ring(true);
        bell.ring(false);  //打下課鈴聲
    }

結(jié)果:

上課鈴響!
老師開(kāi)始上課...
同學(xué)們豪直,上課了...
下課鈴響珠移!
老師下課...
同學(xué)們,下課了...

3. Observer模式總結(jié)

Observer模式優(yōu)點(diǎn):

  • 降低了目標(biāo)與觀察者之間的耦合關(guān)系钧惧,兩者之間是抽象耦合關(guān)系。
  • 目標(biāo)與觀察者之間建立了一套觸發(fā)機(jī)制懈玻。

Observer模式缺點(diǎn):

  • 目標(biāo)與觀察者之間的依賴關(guān)系并沒(méi)有完全解除乾颁,而且有可能出現(xiàn)循環(huán)引用艺栈。
  • 當(dāng)觀察者對(duì)象很多時(shí)湾盒,通知的發(fā)布會(huì)花費(fèi)很多時(shí)間,影響程序的效率毅人。

Observer模式應(yīng)用:

  • MVC模式,Model丈莺、View送丰、Controller,并且Model里面的操作不依賴于具體形式的內(nèi)部模型蚪战,通常情況下:
    一個(gè)Model對(duì)應(yīng)多個(gè)View,這里也是使用Observer設(shè)計(jì)模式最多的地方


    MVC在observer的應(yīng)用示例.png

Observer模式與Mediator模式:

  • 在Mediator模式中瞎疼,有時(shí)會(huì)使用Observer 模式來(lái)實(shí)現(xiàn)Mediator角色與Colleague角色之間的通信壁畸。
  • 就“發(fā)送狀態(tài)變化通知”這一點(diǎn)而言贼急,Mediator模式與Observer模式是類似的太抓。不過(guò),兩種模式中走敌,通知的目的和視角不同逗噩。
  • 在Mediator模式中,雖然也會(huì)發(fā)送通知异雁,不過(guò)那不過(guò)是為了對(duì)Colleague角色進(jìn)行仲裁而已。
    而在Observer模式中项炼,將Subject角色的狀態(tài)變化通知給Observer角色的目的則主要是為了使Subject角色和Observer角色同步。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末驱闷,一起剝皮案震驚了整個(gè)濱河市空免,隨后出現(xiàn)的幾起案子盆耽,更是在濱河造成了極大的恐慌,老刑警劉巖坝咐,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件析恢,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡映挂,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)帽撑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)鞍时,“玉大人,你說(shuō)我怎么就攤上這事及塘。” “怎么了笙僚?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵味咳,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我槽驶,道長(zhǎng),這世上最難降的妖魔是什么掂铐? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮爆班,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘柿菩。我一直安慰自己雨涛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布凉泄。 她就那樣靜靜地躺著,像睡著了一般后众。 火紅的嫁衣襯著肌膚如雪颅拦。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,764評(píng)論 1 290
  • 那天拗盒,我揣著相機(jī)與錄音,去河邊找鬼陡蝇。 笑死哮肚,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的允趟。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼涣楷,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼抗碰!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起弧蝇,我...
    開(kāi)封第一講書(shū)人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤折砸,失蹤者是張志新(化名)和其女友劉穎睦授,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體去枷,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡是复,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片斑鼻。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蜀备,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情碾阁,我是刑警寧澤些楣,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站愁茁,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏嘶居。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一邮屁、第九天 我趴在偏房一處隱蔽的房頂上張望菠齿。 院中可真熱鬧,春花似錦绳匀、人聲如沸民珍。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)逆趣。三九已至,卻和暖如春宣渗,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背痕囱。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留傻粘,地道東北人帮掉。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蟆炊,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子涩搓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348