菜鳥成長系列-觀察者模式

最近想深刻研究下響應式編程,做爲基礎頗有必要來把觀察者模式擼一遍;一開始我是以爲很easy,而後就直接開擼了,擼着擼着發現擼不動了。由於我忽然不太明白這個模式了,說好的觀察者,到底發佈-訂閱的二者執行者誰纔是觀察者?又或者說還有其餘角色?可是根據《JAVA與模式》一書中的結構,並無額外的角色出現。java

思考中....,好吧想不出來....,跑步去...編程

跑步時我給本身羅列了幾個問題:後端

這裏先拋出定義:GOF給觀察者模式以下定義:定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,全部依賴於它的對象都獲得通知並被自動更新。設計模式

  • 既然是對象狀態發生變動,那麼究竟是誰的狀態發生了變動,又致使了誰被通知。
  • 觀察者模式既然又能夠稱之爲「發佈-訂閱模式」,那麼對應起來,觀察者到底承當了「發佈」的角色仍是「訂閱」的角色。就是說觀察者究竟是主動的仍是被動的?
  • 被觀察者又幹了什麼事?它是主動的仍是被動的角色?

這裏因爲一些定式思惟,總會以爲既然是「被觀察者」,那麼這個「被」字就是否是就代表「被觀察者」是被動接受變動的一方,也就是接受通知的一方呢?微信

以前我也是走到這個衚衕裏了,程序寫完總以爲哪裏不對;回過頭看,仍是本身太年輕,沒有get到哪些大佬們的點。app

先來看程序;這裏用掘金來打個比方,個人博客glmmaper做爲被觀察者,也就是發佈者。掘金小夥伴們做爲觀察者,也就是訂閱者。ide

具體邏輯:小夥伴們(訂閱者)關注(訂閱)了個人博客(發佈者),若是我發佈了一篇文章(狀態變動),就會通知(推送消息)全部關注個人小夥伴。spa

package com.glmapper.designmode.observor;
/** * @description: 抽象主題接口 * @email: <a href="glmapper_2018@163.com"></a> * @author: 磊叔 * @date: 18/4/22 */
public interface Subject {
    /** * 新增關注者 * @param observer 關注的小夥伴 */
    void addFocusObserver(Observer observer);

    /** * 取消關注 * @param observer 取消關注的小夥伴 */
    void removeFocusObserver(Observer observer);

    /** * 通知機制,通知機制由相關事件來觸發,好比說發佈文章 * @param blogName 博客名 * @param articleName 文章名 */
    void notifyObservers(String blogName,String articleName);
}
複製代碼

三個方法,一個是博客主頁增長了一個關注者;一個是博客主頁有小夥伴取消的關注(對於博客來講就是移除一個關注者,這裏不知道是否也會以爲彆扭?明明你取消的關注,爲啥說成是我移除你,也就是不讓你關注了,還能這麼玩?這裏確定是須要在引入其餘的一些輔助機制,好比說你在客戶端發起了一個取消關注的請求,後端處理的時候掘金的工程師們就是在個人關注列表中將你移除的,嗯,這麼一想確實是我不讓你關注了。😄....);最後一個方法是發起一個通知。下面是一個具體的博客,好比說是glmapper;設計

package com.glmapper.designmode.observor;

import java.util.ArrayList;
import java.util.List;

/** * @description: 這個是具體發佈者,這裏比喻成個人博客glmapper * @email: <a href="glmapper_2018@163.com"></a> * @author: 磊叔 * @date: 18/4/22 */
public class ConcreteSubject implements Subject {
    /** 個人當前關注列表 */
    List<Observer> Observers = new ArrayList<>();
    /** 個人博客名 :求關注 */
    private static final String blogName = "glmapper";

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

    @Override
    public void removeFocusObserver(Observer observer) {
        Observers.remove(observer);
    }

    @Override
    public void notifyObservers(String blogName,String articleName) {
        for (Observer observer:Observers) {
            observer.update(blogName,articleName);
        }
    }
    
    /** * 這裏是發佈文章,觸發通知事件 */
    public void publishArticle(String articleName){
        notifyObservers(blogName,articleName);
    }
}

複製代碼

前面提到,通知事件確定是因爲某些狀態發生變動了,纔會進行通知,這裏就能夠比方爲我發佈了一篇博客,而後通知你(這裏只能假如你關注了)。再來看觀察者:code

package com.glmapper.designmode.observor;

/** * @description: 訂閱者抽象接口 * @email: <a href="glmapper_2018@163.com"></a> * @author: 磊叔 * @date: 18/4/22 */
public interface Observer {
    /** * 調用此方法會更新狀態,作出相應的動做 * @param blogName * @param articleName */
    void update(String blogName,String articleName);
}
複製代碼

抽象訂閱者,有一個update方法,通知你去作出相應的動做,具體動做每一個觀察者均可能不一樣。

package com.glmapper.designmode.observor;

/** * @description: 這個是具體訂閱者,這裏能夠比喻成博客關注者, * 收到變動信息以後須要作出相應的動做 * @email: <a href="glmapper_2018@163.com"></a> * @author: 磊叔 * @date: 18/4/22 */
public class ConcreteObserver implements Observer {

    @Override
    public void update(String blogName,String articleName) {
        System.out.println(blogName+"發佈了新的文章,文章名爲:"+articleName);
        read(articleName);
    }

    private void read(String articleName){
        System.out.println("即將閱讀 "+articleName+" 這篇文章");
    }
}
複製代碼

上面是一個具體的關注者,加入說就是你。博客更新以後發了一個通知給你(掘金app推送的消息),而後你點了一下,這個也是一種動做。例子中舉的是read,就是關注者作出閱讀的動做。

看下最後的運行結果:

package com.glmapper.designmode.observor;

/** * @description: [描述文本] * @email: <a href="glmapper_2018@163.com"></a> * @author: 磊叔 * @date: 18/4/22 */
public class MyMainIndex{

    public static void main(String[] args) {
        //博客主體
        ConcreteSubject subject = new ConcreteSubject();
        //關注者:handSome是帥氣的意思
        Observer handSome = new ConcreteObserver();
        //增長一個關注者
        subject.addFocusObserver(handSome);
        //發一篇文章
        subject.publishArticle("設計模式-觀察者模式");
    }

}


glmapper發佈了新的文章,文章名爲:設計模式-觀察者模式
即將閱讀 設計模式-觀察者模式 這篇文章
複製代碼

酒桶說:啊,歡樂時光老是短暫的

因此做爲積累,仍是須要將一些基本的概念來羅列一下的。

觀察者模式類圖

主要角色:

  • 抽象主題角色(Subject:主題角色將全部對觀察者對象的引用保存在一個集合中,每一個主題能夠有任意多個觀察者。抽象主題提供了增長和刪除等觀察者對象的接口。
  • 抽象觀察者角色(Observer):爲全部的具體觀察者定義一個接口,在觀察的主題發生改變時更新本身。
  • 具體主題角色(ConcreteSubject)(1個):存儲相關狀態到具體觀察者對象,當具體主題的內部狀態改變時,給全部登記過的觀察者發出通知。具體主題角色一般用一個具體子類實現。
  • 具體觀察者角色(ConcretedObserver)(多個):存儲一個具體主題對象,存儲相關狀態,實現抽象觀察者角色所要求的更新接口,以使得其自身狀態和主題的狀態保持一致。

具體關係:

  • 抽象主題(Subject)(接口)-->被具體主題(ConcreteSubject)角色(1個)實現

  • 抽象觀察者(Observer)(接口)-->被具體觀察者(ConcretedObserver)角色(N個)實現

  • 觀察者對象載入主題方法,並在主題方法中調用觀察者對象實現的接口方法update來讓本身發生變動響應。

一些場景:

  • 當對一個對象的的改動會引起其餘對象的變更時,並且你沒法預測有多少個對象須要被改動。
  • 當一個對象須要有能力通知其餘對象,且不須要了解這些對象是什麼類型時。

基於發佈訂閱的具體實現例子仍是不少的,比較典型的就是這種訂閱一個博客,而後博客更新推送;還有微信公衆號,服務號這些。

到這裏咱們再回過頭來看一開始留下的幾個問題:

  • 被觀察者的狀態發生變動,而後「主動通知」觀察者,並非說,觀察者主動去獲取通知。
  • 被觀察者是消息發佈者,觀察者是消息訂閱者;觀察者是被動接受者。
  • 被觀察者的做用就是存儲當前的觀察者列表,而後提供一些通知機制來告訴觀察者本身發生了狀態變動,是主動者。

OK,觀察者模式就擼到這裏,也歡迎小夥伴們提出本身珍貴的意見;有寫的不當之處煩請及時提出。

播報:菜鳥成長系列又開始更新了....

相關文章
相關標籤/搜索