深入淺出 觀察者模式

寫在前面: 我是「揚帆向海」,這個暱稱來源於我的名字以及女朋友的名字。我熱愛技術、熱愛開源、熱愛編程。技術是開源的、知識是共享的

這博客是對自己學習的一點點總結及記錄,如果您對 Java算法 感興趣,可以關注我的動態,我們一起學習。

用知識改變命運,讓我們的家人過上更好的生活

在這裏插入圖片描述

一、定義與組成部分

1. 定義

觀察者(Observer)模式 又名發佈-訂閱(Publish/Subscribe)模式。GOF 給觀察者模式如下定義:

定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。

面向對象設計的一個重要原則——單一職責原則。系統的每個對象應該將重點放在問題域中的離散抽象上。因此理想的情況下,一個對象只做一件事情。這樣在開發中也就帶來了諸多的好處:提供了重用性和維護性,也是進行重構的良好的基礎。

2. 組成部分

觀察者模式由以下幾部分組成

  1. 抽象目標角色(Subject):目標角色知道它的觀察者,可以有任意多個觀察者觀察同一個目標。並且提供註冊和刪除觀察者對象的接口。目標角色往往由抽象類或者接口來實現。
  2. 抽象觀察者角色(Observer):爲那些在目標發生改變時需要獲得通知的對象定義一個更新接口。抽象觀察者角色主要由抽象類或者接口來實現。
  3. 具體目標角色(Concrete Subject):將有關狀態存入各個Concrete Observer 對象。當它的狀態發生改變時, 向它的各個觀察者發出通知。
  4. 具體觀察者角色(Concrete Observer):存儲有關狀態,這些狀態應與目標的狀態保持一致。實現Observer 的更新接口以使自身狀態與目標的狀態保持一致。在本角色內也可以維護一個指向Concrete Subject 對象的引用。

使用觀察者模式的類圖,這樣能將關係清晰的表達出來。

在這裏插入圖片描述

在 Subject 這個抽象類中,提供了上面提到的功能,而且存在一個通知方法:notify。

還可以看到Subject 和ConcreteSubject 之間可以說是使用了模板模式(這個模式真是簡單普遍到一不小心就用到了)。

這樣當具體目標角色的狀態發生改變,按照約定則會去調用通知方法,在這個方法中則會根據目標角色中註冊的觀察者名單來逐個調用相應的update 方法來調整觀察者的狀態。

這樣觀察者模式就走完了一個流程。

二、實現觀察者模式

MySubject類就是我們的主對象,Observer1和Observer2是依賴於MySubject的對象,當MySubject變化時,Observer1和Observer2必然變化。

AbstractSubject類中定義着需要監控的對象列表,可以對其進行修改:增加或刪除被監控對象,且當MySubject變化時,負責通知在列表內存在的對象。

Observer接口

public interface Observer {
    public void update();
}

實現類:Observer1

public class Observer1 implements Observer {
    @Override
    public void update() {
        System.out.println("observer1 接收到了!");
    }
}

實現類:Observer2

public class Observer2 implements Observer{
    @Override
    public void update() {
        System.out.println("observer2 接收到了!");
    }
}

Subject接口

public interface Subject {

    /**
     * 增加觀察者
     *
     * @param observer
     */
    public void add(Observer observer);

    /**
     * 刪除觀察者
     * @param observer
     */
    public void del(Observer observer);

    /**
     * 通知所有的觀察者
     */
    public void notifyObservers();

    /**
     * 自身的操作
     */
    public void operation();
}

Subject實現類

public abstract class AbstractSubject implements Subject {
    private Vector<Observer> vector = new Vector<Observer>();

    @Override
    public void add(Observer observer) {
        vector.add(observer);
    }

    @Override
    public void del(Observer observer) {
        vector.remove(observer);
    }

    @Override
    public void notifyObservers() {
        Enumeration<Observer> enumo = vector.elements();
        while (enumo.hasMoreElements()) {
            enumo.nextElement().update();
        }
    }

    @Override
    public void operation() {

    }
}

MySubject類

public class MySubject extends AbstractSubject {
    @Override
    public void operation() {
        System.out.println("主對象的狀態發生了改變!");
        notifyObservers();
    }
}

測試類:

public class Test {
    public static void main(String[] args) {
        Subject subject = new MySubject();
        subject.add(new Observer1());
        subject.add(new Observer2());
        subject.operation();
    }
}

測試結果:

在這裏插入圖片描述

三、 總結

  1. 觀察者模式 主要解決了什麼問題?

一個對象狀態改變給其他對象通知的問題,而且要考慮到易用和低耦合,保證高度的協作。

  1. 如何解決?

使用面向對象技術,可以將這種依賴關係弱化。

  1. 觀察者模式 何時使用?

一個對象(目標對象)的狀態發生改變,所有的依賴對象(觀察者對象)都將得到通知,進行廣播通知。

  1. 觀察者模式 的優缺點

【優點】

① 觀察者和被觀察者是抽象耦合的。
② 建立一套觸發機制。

【缺點】

① 如果一個被觀察者對象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間。
②如果在觀察者和觀察目標之間有循環依賴的話,觀察目標會觸發它們之間進行循環調用,可能導致系統崩潰。
③ 觀察者模式沒有相應的機制讓觀察者知道所觀察的目標對象是怎麼發生變化的,而僅僅只是知道觀察目標發生了變化。

  1. 觀察者模式 的使用場景

一個抽象模型有兩個方面,其中一個方面依賴於另一個方面。將這些方面封裝在獨立的對象中使它們可以各自獨立地改變和複用。

一個對象的改變將導致其他一個或多個對象也發生改變,而不知道具體有多少對象將發生改變,可以降低對象之間的耦合度。

一個對象必須通知其他對象,而並不知道這些對象是誰。

需要在系統中創建一個觸發鏈,A對象的行爲將影響B對象,B對象的行爲將影響C對象……,可以使用觀察者模式創建一種鏈式觸發機制。

  1. 觀察者模式 的注意事項

① JAVA 中已經有了對觀察者模式的支持類。
② 避免循環引用。
③ 如果順序執行,某一觀察者錯誤會導致系統卡殼,一般採用異步方式。


由於水平有限,博客中難免會有一些錯誤,有紕漏之處懇請各位大佬不吝賜教!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章