個人Java設計模式-觀察者模式

相信你們都有看過《喜洋洋與灰太狼》,說的是灰太狼和羊族的「鬥爭」,而每次的結果都是灰太狼一飛沖天,伴隨着一句「我還會回來的......」。爲灰太狼感到悲哀,抓不到羊,在家也被老婆平底鍋虐待。灰太狼爲何會這麼背?java

很簡單,灰太狼自己就有「暴露行蹤」的屬性,羊咩咩就能知曉灰太狼要幹嗎,不背纔怪呢。git

爲了幫助灰太狼擺脫被老婆平底鍋抽的悲劇,發起了「解救灰太狼」的行動,必需要知道觀察者模式github

1、觀察者模式

定義

觀察者模式又叫作發佈-訂閱模式,定義了對象間一對多的依賴關係,使得當對象狀態發生變化時,全部依賴它的對象都會收到通知而且自動更新本身。設計模式

特色

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

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

UML

觀察者模式UML圖

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

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

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

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

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

2、實戰

灰太狼具備被觀察者屬性,喜洋洋這些羊咩咩一直都在觀察者灰太狼,因此羊咩咩們是觀察者。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();
    }

}
複製代碼

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

增長了觀察者:喜羊羊

增長了觀察者:懶羊羊

灰太狼:我要搞事情了

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

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

刪除了觀察者:喜羊羊

灰太狼:我要搞事情了

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

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

3、觀察者模式的優缺點

優勢

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

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

缺點

1)若是觀察者太多,被觀察者通知觀察者消耗的時間不少,影響系統的性能。

2)當觀察者集合中的某一觀察者錯誤時就會致使系統卡殼,所以通常會採用異步方式。

4、比較

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

總結

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

設計模式Java源碼GitHub下載github.com/jetLee92/De…

相關文章
相關標籤/搜索