我的Java設計模式-觀察者模式

相信大家都有看過《喜洋洋與灰太狼》,說的是灰太狼和羊族的“斗爭”,而每次的結果都是灰太狼一飛沖天,伴隨著一句“我還會回來的......”。為灰太狼感到悲哀,抓不到羊,在家也被老婆平底鍋虐待。灰太狼為什么會這么背?

很簡單,灰太狼本身就有“暴露行蹤”的屬性,羊咩咩就能知曉灰太狼要干嘛,不背才怪呢。

為了幫助灰太狼擺脫被老婆平底鍋抽的悲劇,發起了“解救灰太狼”的行動,必須要知道觀察者模式

一、觀察者模式

定義

觀察者模式又叫做發布-訂閱模式,定義了對象間一對多的依賴關系,使得當對象狀態發生變化時,所有依賴它的對象都會收到通知并且自動更新自己。

特點

1)被觀察者需要持有一個或者多個觀察者對象。

2)系統中一個模塊的變化,某些模塊也會跟隨著變化。

UML

觀察者模式UML圖

從上面的UML可以看出來,觀察者模式設計到的角色有如下四個:

- 抽象被觀察者角色:定義了動態增加、刪除以及通知觀察者對象的方法,職責就是管理和通知觀察者。持有觀察者對象的集合。

- 具體被觀察者角色:一般繼承抽象被觀察者,實現自己本身的業務邏輯,當狀態發生改變時發起通知。

- 抽象觀察者角色:提供一個接口,定義了觀察者收到通知時更新自己的方法。

- 具體觀察者角色:實現抽象觀察者接口,處理不同具體觀察者的不同業務邏輯。

二、實戰

灰太狼具有被觀察者屬性,喜洋洋這些羊咩咩一直都在觀察者灰太狼,所以羊咩咩們是觀察者。OK,角色確定了,看看具體是怎么實現的...

抽象被觀察者代碼如下:

public abstract class Subject {

    /**
     * 觀察者對象的集合
     */
    private List<Observer> observerList = new ArrayList<>();

    /**
     * 登記觀察者
     *
     * @param observer
     */
    public void attach(Observer observer) {
        observerList.add(observer);
        System.out.println("增加了觀察者:" + observer.getName());
    }

    /**
     * 刪除觀察者
     *
     * @param observer
     */
    public void dettach(Observer observer) {
        observerList.remove(observer);
        System.out.println("刪除了觀察者:" + observer.getName());
    }

    /**
     * 通知所有觀察者
     */
    public void notifyObserver() {
        for (Observer observer : observerList) {
            observer.update("灰太狼要搞事情了");
        }
    }

}

灰太狼是具體被觀察者,繼承抽象被觀察者,代碼如下:

public class Wolf extends Subject {

    public void invade(){

        System.out.println("灰太狼:我要搞事情了");
        // 通知所有觀察者
        notifyObserver();
    }

}

抽象觀察者代碼如下:

public interface Observer {

    String getName();

    /**
     * 通知更新方法
     *
     * @param msg
     */
    public void update(String msg);

}

喜羊羊是具體觀察者,實現抽象觀察者,代碼如下:

public class PleasantSheep implements Observer{

    @Override
    public String getName() {
        return "喜羊羊";
    }

    /**
     * 具體業務邏輯
     */
    @Override
    public void update(String msg) {
        System.out.println("喜羊羊收到通知:" + msg);
    }

}

接下來看客戶端如何把觀察者模式跑起來,代碼如下:

public class Client {

    public static void main(String[] args) {
        // 灰太狼--被觀察者
        Wolf wolf = new Wolf();
        // 喜羊羊--觀察者
        Observer pleasantSheep = new PleasantSheep();
        // 登記觀察者
        wolf.attach(pleasantSheep);
        // 灰太狼入侵
        wolf.invade();
    }

}

運行客戶端代碼,結果如下:

增加了觀察者:喜羊羊

灰太狼:我要搞事情了

喜羊羊收到通知:灰太狼要搞事情了

看到了吧,灰太狼這不是自找虐嗎!搞事情還要發通知,活該被平底鍋拍飛。灰太狼不止通知了喜羊羊,還通知了懶羊羊。

懶羊羊也是具體觀察者,代碼如下:

public class LazySheep implements Observer {

    @Override
    public String getName() {
        return "懶羊羊";
    }

    @Override
    public void update(String msg) {
        System.out.println("懶羊羊收到通知:" + msg);
    }
    
}

客戶端代碼如下:

public class Client {

    public static void main(String[] args) {
        // 灰太狼--被觀察者
        Wolf wolf = new Wolf();

        // 喜羊羊--觀察者
        Observer pleasantSheep = new PleasantSheep();
        // 登記觀察者
        wolf.attach(pleasantSheep);

        // 懶羊羊--觀察者
        Observer lazySheep = new LazySheep();
        // 登記觀察者
        wolf.attach(lazySheep);
        
        // 灰太狼入侵
        wolf.invade();
    }

}

上面客戶端代碼創建了一個懶羊羊觀察者,添加了觀察者集合中,這樣懶羊羊也會受到通知,運行結果如下:

增加了觀察者:喜羊羊

增加了觀察者:懶羊羊

灰太狼:我要搞事情了

喜羊羊收到通知:灰太狼要搞事情了

懶羊羊收到通知:灰太狼要搞事情了

那如何幫助灰太狼擺脫這個命運呢,把觀察者從集合中移除就OK了,代碼如下:

public class Client {

    public static void main(String[] args) {
        // 灰太狼--被觀察者
        Wolf wolf = new Wolf();

        // 喜羊羊--觀察者
        Observer pleasantSheep = new PleasantSheep();
        // 登記觀察者
        wolf.attach(pleasantSheep);

        // 懶羊羊--觀察者
        Observer lazySheep = new LazySheep();
        // 登記觀察者
        wolf.attach(lazySheep);

        // 灰太狼入侵
        wolf.invade();
        
        // 刪除觀察者
        wolf.dettach(pleasantSheep);
        
        wolf.invade();
    }

}

再次運行客戶端,結果如下:

增加了觀察者:喜羊羊

增加了觀察者:懶羊羊

灰太狼:我要搞事情了

喜羊羊收到通知:灰太狼要搞事情了

懶羊羊收到通知:灰太狼要搞事情了

刪除了觀察者:喜羊羊

灰太狼:我要搞事情了

懶羊羊收到通知:灰太狼要搞事情了

可以看到,把喜羊羊從觀察者集合中移除了,它就不會再收到通知。

三、觀察者模式的優缺點

優點

1)觀察者和被觀察者之間抽象耦合。觀察者模式容易擴展,被觀察者只持有觀察者集合,并不需要知道具體觀察者內部的實現。

2)對象之間的保持高度的協作。當被觀察者發生變化時,所有被觀察者都會通知到,然后做出相應的動作。

缺點

1)如果觀察者太多,被觀察者通知觀察者消耗的時間很多,影響系統的性能。

2)當觀察者集合中的某一觀察者錯誤時就會導致系統卡殼,因此一般會采用異步方式。

四、比較

跟代理模式對比:觀察者模式和代理模式主要區別在它們功能不一樣,觀察者模式強調的是被觀察者反饋結果,而代理模式是同根負責做同樣的事情。

總結

在Java中已經提供了Observable類以及一個Observer接口,也就是說Java已經實現了觀察者模式的定義,可看出觀察者模式在程序系統中的使用率是很高的,不單是Java,Android中也經常看到觀察者模式的運用,比如OnClickListener,Rxjava等。下一篇會補上屬于創建型模式的原型模式,下回分解,再見。

設計模式Java源碼GitHub下載https://github.com/jetLee92/DesignPattern

AndroidJet的開發之路.jpg
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,570評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,505評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,786評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,219評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,438評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,971評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,796評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,995評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,230評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,697評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容

  • 1 場景問題# 1.1 訂閱報紙的過程## 來考慮實際生活中訂閱報紙的過程,這里簡單總結了一下,訂閱報紙的基本流程...
    七寸知架構閱讀 4,641評論 5 57
  • 設計模式匯總 一、基礎知識 1. 設計模式概述 定義:設計模式(Design Pattern)是一套被反復使用、多...
    MinoyJet閱讀 3,960評論 1 15
  • “本文參加#未完待續,就要表白#活動,本人承諾,文章內容為原創,且未在其他平臺發表過。 陜理工的校園里,不僅充滿了...
    dhdhdh閱讀 159評論 0 0
  • 昨晚姥爺和姥姥接,按照以前,我會因為教育理念不一致維護,昨天我作為旁觀者,默默的看著跟姥爺姥姥的溝通,非常有意思 ...
    文刀祐閱讀 344評論 0 0
  • 今天,早上回到辦公室經理已經比我早回到 我今天吃了一個菠蘿包 明天打算買豆腐花 明天又開始周三了 今天老板回來了,...
    歲月靜好_LI閱讀 181評論 4 0