深入理解[觀察者模式]原理與技術

像風一樣i發表於2019-05-24

觀察者模式(Observer Pattern)也叫做釋出-訂閱(Publish/Subscribe)模式、模型-檢視(Model/View)模式。這個模式的一個最重要的作用就是解耦。也就是將被觀察者和觀察者進行解耦,使得他們之間的依賴性更小,甚至做到毫無依賴。

觀察者模式的定義:該模式定義了物件之間的一對多依賴關係,Subject 物件是一,Observer 物件是多。當 Subject 物件的狀態發生改變時,所有依賴於該 Subject 物件的 Observer 物件都會得到通知,並且自動更新。

仔細分析定義,要精確理解觀察者模式主要注意三點:

  1. 定義了物件間的一對多依賴關係。

  2. 當 Subject 物件的狀態發生改變時,所有依賴於該 Subject 物件的 Observer 物件都會得到通知。

  3. Observer 物件得到通知後,會自動更新,而不是被動。

經過上面的分析,下面我用程式碼簡單實現上述邏輯。

1.首先需要定義一個觀察者物件,內部含有data資料(getter、setter、構造方法、toString)。

public class Observer {
    private String data;

    public Observer(String data) {
        this.data = data;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "Observer{" +
                "data='" + data + '\'' +
                '}';
    }
}

2.其次定義主題物件,主題物件內部提供觀察者繫結(register)的介面,並且可以更新(update)所繫結的觀察者物件。

public class Subject {
    private List<Observer> list = new ArrayList<>();

    public void register(Observer observer){
        list.add(observer);
    }

    public void update(){
        list.forEach(observer -> {
            observer.setData("new");
            System.out.println(observer.toString());
        });
    }

}

3.最後就是main方法。

    public static void main(String[] args) {
        Subject subject = new Subject();
        for (int i = 0; i < 3; i++) {
            Observer observer = new Observer("old");
            subject.register(observer);
            System.out.println(observer.toString());
        }
        System.out.println("update...");
        subject.update();
    }

控制檯列印

Observer{data='old'}
Observer{data='old'}
Observer{data='old'}
update...
Observer{data='new'}
Observer{data='new'}
Observer{data='new'}

看到這裡你也許會問:這就是觀察者模式?這麼簡單?你莫不是在逗我?

是的,這就是觀察者模式。我們從觀察者模式的定義出發,抽取出關鍵的3點核心思想,對比程式碼和三點思想,是不是完美一致?百度一下"觀察者模式",實現邏輯大都是複雜高深,其實就核心的思想來說,上面的示例足夠了,其它擴充套件要以具體的業務需求來決定。比如:

  1. Subject 角色是應該定義成類?比如 內建的 java.util.Observable;還是應該定義成介面,以規避Java不支援多重繼承的問題?

  2. 應該在什麼時候訂閱主題(或者說註冊觀察者)?是例項化觀察者物件的同時?還是由客戶自主決定?

  3. 是否應該實現取消訂閱功能(或者說取消註冊)?

  4. 主題物件通知觀察者時,是否攜帶訊息?換句話說,是“推”訊息?還是“拉”訊息?

  5. 是否支援多執行緒?

相關文章