觀察者模式

一、概述bash

觀察者模式是一種對象行爲型模式,定義了一對多的依賴關係,讓多個觀察者對象同時監聽某個主題對象。這個主題對象會通知全部的觀察者對象,使他們自動更新本身。 它關鍵對象是觀察目標和觀察者,每一個觀察者都將即時更新本身的狀態,以與目標狀態同步,這種交互也稱爲發佈-訂閱(publishsubscribe)。目標是通知的發佈者,它發出通知時並不須要知道誰是它的觀察者,能夠有任意數目的觀察者訂閱它並接收通知。異步

二、模式結構 ide

圖片

觀察者涉及角色:測試

  • 抽象主題(Subject)角色:通常用一個抽象類或者接口實現,把全部對觀察者對象的引用保存在一個List裏,每一個主題能夠有任何數量的觀察者。抽象主題提供一個接口,能夠增長和刪除觀察者對象。
  • 抽象觀察(Observer)角色:爲全部具體的觀察者定義一個接口,在獲得主題通知時更新本身。
  • 具體主題(ConcreteSubject)角色:將有關狀態存入具體觀察者對象;在具體主題的內部狀態改變時,給全部登記過的觀察者發出通知。
  • 具體觀察者(ConcreteObserver)角色:實現抽象觀察者角色所要求的更新接口,以便使自己的狀態與主題的狀態像協調。

三、使用場景ui

  • 一個抽象模型有兩個方面,其中一個方面依賴於另外一個方面。將這些方面封裝在獨立的對象中使它們能夠各自獨立地改變和複用。
  • 一個對象的改變將致使其餘一個或多個對象也發生改變,而不知道具體有多少對象將發生改變,能夠下降對象之間的耦合度。
  • 須要在系統中建立一個觸發鏈,A對象的行爲將影響B對象,B對象的行爲將影響C對象等,能夠使用觀察者模式建立一種鏈式觸發機制。

四、優缺點this

優勢:spa

  • 符合「開閉原則」要求
  • 解除耦合,讓耦合雙方都依賴於抽象,而不是依賴於具體。
  • 支持廣播通信。被觀察者會向全部的登記過的觀察者發出通知

缺點:線程

  • 一個觀察目標對象有不少直接和間接的觀察者的話,將全部的觀察者都通知到會花費不少時間。
  • 觀察者之間有循環依賴的話,被觀察者會觸發它們之間進行循環調用,致使系統崩潰
  • 觀察者的通知是經過另外的線程進行異步投遞的話,系統必須保證投遞是以自恰的方式進行的
  • 觀察者模式能夠隨時使觀察者知道所觀察的對象發生了變化,可是觀察者模式沒有相應的機制使觀察者知道所觀察的對象是怎麼發生變化的

五、實例日誌

首先定義被觀察者code

public interface Subject {
    public void attach(Observer obj);

    public void detach(Observer obj);

    public void notifyObserver(String topicName);
}
複製代碼

在建立一個關聯的觀察者

public interface Observer {
    public void update(String topicName);
}
複製代碼

關聯已經創建,如今實現具體的主題

public class Topic implements Subject {
    private List<Observer> list;

    public Topic() {
        list = new ArrayList<>();
    }

    @Override
    public void attach(Observer obj) {
        if (obj == null) {
            return;
        }
        if (!list.contains(obj)) {
            list.add(obj);
        }
    }

    @Override
    public void detach(Observer obj) {
        if (list.contains(obj)) {
            list.remove(obj);
        }
    }

    @Override
    public void notifyObserver(String topicName) {
        for (Observer observer : list) {
            observer.update(topicName);
        }
    }
}
複製代碼

具體觀察者的實現,他們將一直關注subject對象。

public class TopicSubscriber implements Observer {

    private String name;

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

    @Override
    public void update(String topicName) {
        System.out.println(name + " topic name update:" + topicName);
    }
}
複製代碼

測試,定義三個具體的觀察者,而後註銷一個觀察者。

public void testTopic() {
    Topic topic = new Topic();
    TopicSubscriber sub1 = new TopicSubscriber("sub1");
    TopicSubscriber sub2 = new TopicSubscriber("sub2");
    TopicSubscriber sub3 = new TopicSubscriber("sub3");
    topic.attach(sub1);
    topic.attach(sub2);
    topic.attach(sub3);
    topic.notifyObserver("new topic1");
    topic.detach(sub3);
    topic.notifyObserver("new topic2");
}
打印日誌
sub1 topic name update:new topic1
sub2 topic name update:new topic1
sub3 topic name update:new topic1
sub1 topic name update:new topic2
sub2 topic name update:new topic2
複製代碼
相關文章
相關標籤/搜索