設計模式:觀察者模式 ——— 城管來了,攤主快跑

鄙人薛某發表於2019-07-31

前言

時間飛逝,轉眼初夏已過,尤記得以前讀大學的時候,夏季最快樂的時光就是和小夥伴們在球場上打完球后去校門附近的燒烤攤擼串喝酒,那種感覺真是大快人心,怎一個爽字了得。不過有時也會遇到特殊情況,在擼串時攤主突然告知要收攤,連忙向我們賠禮道歉,原因是城管將至。我們無奈只能中斷擼串過程,帶著無法盡興的鬱悶心情離開.......

好吧,扯遠了,說那麼多廢話也是想介紹兩個角色,城管和燒烤攤主,這兩個角色其實就相當於觀察者模式中的被觀察者和觀察者,他們的活動過程其實就類似於觀察者模式。

觀察者模式

開始介紹觀察者模式,毫無疑問,先說下它的定義。

定義

定義物件間一種一對多的依賴關係,使得每當一個物件改變狀態,則所有依賴於它的物件都會得到通知並被自動更新。

其實就是釋出-訂閱模式,在實際的專案中非常的常見,比如微信公眾號的訊息推送就是觀察者模式的最直接的應用。

通用類圖

設計模式:觀察者模式 ——— 城管來了,攤主快跑
上面的類圖包含了四個角色,分別是:

  • Subject 抽象被觀察者:定義被觀察者必須實現的職責,它必須能夠動態地增加、取消觀察者。它一般是抽象類或者是實現類,僅僅完成作為被觀察者必須實現的職責:管理觀察者並通知觀察者。

  • Observer 抽象觀察者:為所有的具體觀察者定義一個介面,在得到主題通知時更新自己。

  • ConcreteSubject 具體被觀察者:定義被觀察者自己的業務邏輯,同時定義對哪些事件進行通知。

  • ConcreteObserver 具體觀察者:實現抽象觀察者角色所需要的更新介面,各個觀察者有自己的處理邏輯。

實際例子

講完了觀察者模式的角色後,我們用實戰例子來演示一下,就拿城管和小攤攤主舉例好了,城管對應著觀察者模式中的被觀察者,而攤主就對應著觀察者。OK,角色分配好了,我們開始寫程式碼吧。

抽象被觀察者

public abstract class Subject {
    //定義一個觀察者陣列
    private List<Observer> obs = new ArrayList<>();

    //增加一個觀察者
    public void addObserver(Observer o) {
        this.obs.add(o);
    }

    //刪除一個觀察者
    public void delObserver(Observer o) {
        this.obs.remove(o);
    }

    //通知所有觀察者
    public void notifyObservers() {
        for (Observer o : this.obs) {
            o.update();
        }
    }
}

具體被觀察者

也就是城管,不知道英文怎麼拼,用Police代替了,

public class Police extends Subject {
    public void chase(){
        System.out.println("城管:我要來了,還不走");
        // 通知所有觀察者
        notifyObservers();
    }
}

抽象觀察者

public interface Observer {
    /**
     * 通知更新
     * @param message
     */
    void update(String message);
}

具體觀察者

public class Vendor implements Observer {
    private String name;
    private String message;

    public Vendor(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        System.out.println(name + " 收到: " + message);
    }
}

場景類

最後用一個場景類驗證一下,

public class Client {

    public static void main(String[] args) {
        // 城管--被觀察者
        Police police = new Police();

        // 燒烤攤主--觀察者
        Observer barbecueVendor = new Vendor("燒烤攤主");

        // 手抓餅攤主--觀察者
        Observer cakeVendor = new Vendor("手抓餅攤主");

        System.out.println("=======增加兩個觀察者=======");
        police.addObserver(barbecueVendor);
        police.addObserver(cakeVendor);
        police.chase();

        System.out.println("=======刪除一個觀察者=======");
        police.delObserver(cakeVendor);
        police.chase();
    }
}

定義一個城管物件和兩個攤主物件,然後執行通知更新的操作,結果如下:

=======增加兩個觀察者=======
城管:我要來了,還不走
燒烤攤主 收到: 城管要來了,大家跑啊
手抓餅攤主 收到: 城管要來了,大家跑啊
=======刪除一個觀察者=======
城管:我要來了,還不走
燒烤攤主 收到: 城管要來了,大家跑啊

可以看到,我們的程式碼能正常增刪觀察者角色,同時也能通知訊息更新,也算是重現了了觀察者模式的流轉過程。

總結

優點

1、觀察者和被觀察者之間抽象耦合。不管是增加觀察者還是被觀察者都非常容易擴充套件,而且在Java中都已經實現的抽象層級的定義,在系統擴充套件方面更是得心應手。

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

缺點

1、如果觀察者太多,被觀察者通知觀察者消耗的時間很多,同時開發和除錯會比較複雜,影響系統的效能。

2、在Java中訊息的通知預設是順序執行,當某一觀察者錯誤時就會導致系統卡殼,因此一般會採用非同步方式。

參考:

《設計模式之禪》

相關文章