觀察者模式解讀

觀察者模式

定義

定義了對象之間的一對多依賴蜀撑,讓多個(gè)觀察者對象同時(shí)監(jiān)聽某一個(gè)主題對象漆改。當(dāng)主題對象發(fā)生變化時(shí)俘枫,它的所有依賴者(觀察者)都會收到通知并更新钟病。

適用場景

關(guān)聯(lián)行為場景返吻,建立一套觸發(fā)機(jī)制

提出需求

用戶訂閱微信公眾號姑子,公眾號更新,用戶接收到通知

需求分析

觀察者模式又叫發(fā)布-訂閱模式测僵。需求中街佑,用戶訂閱微信公眾號,當(dāng)微信公眾號有新的消息時(shí)捍靠,所有訂閱這個(gè)微信公眾號的用戶都可以接收到這個(gè)消息沐旨。這個(gè)就是很典型的發(fā)布訂閱模式。微信公眾號作為被訂閱者(也叫被觀察者)榨婆,用戶訂閱這個(gè)公眾號磁携。用戶就是作為觀察者的角色存在的。

代碼實(shí)現(xiàn)

jdk中已經(jīng)幫我們實(shí)現(xiàn)了觀察者模式良风。java.util.Observable和java.util.Observer颜武。
我們先看下jdk源碼

  • java.util.Observable 被觀察者

package java.util;

/**
 * This class represents an observable object, or "data"
 * in the model-view paradigm. It can be subclassed to represent an
 * object that the application wants to have observed.
 * <p>
 * An observable object can have one or more observers. An observer
 * may be any object that implements interface <tt>Observer</tt>. After an
 * observable instance changes, an application calling the
 * <code>Observable</code>'s <code>notifyObservers</code> method
 * causes all of its observers to be notified of the change by a call
 * to their <code>update</code> method.
 * <p>
 * The order in which notifications will be delivered is unspecified.
 * The default implementation provided in the Observable class will
 * notify Observers in the order in which they registered interest, but
 * subclasses may change this order, use no guaranteed order, deliver
 * notifications on separate threads, or may guarantee that their
 * subclass follows this order, as they choose.
 * <p>
 * Note that this notification mechanism has nothing to do with threads
 * and is completely separate from the <tt>wait</tt> and <tt>notify</tt>
 * mechanism of class <tt>Object</tt>.
 * <p>
 * When an observable object is newly created, its set of observers is
 * empty. Two observers are considered the same if and only if the
 * <tt>equals</tt> method returns true for them.
 *
 * @author  Chris Warth
 * @see     java.util.Observable#notifyObservers()
 * @see     java.util.Observable#notifyObservers(java.lang.Object)
 * @see     java.util.Observer
 * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
 * @since   JDK1.0
 */
public class Observable {
    private boolean changed = false;
    private Vector<Observer> obs;

    /** Construct an Observable with zero Observers. */

    public Observable() {
        obs = new Vector<>();
    }

    /**
     * Adds an observer to the set of observers for this object, provided
     * that it is not the same as some observer already in the set.
     * The order in which notifications will be delivered to multiple
     * observers is not specified. See the class comment.
     *
     * @param   o   an observer to be added.
     * @throws NullPointerException   if the parameter o is null.
     */
    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }

    /**
     * Deletes an observer from the set of observers of this object.
     * Passing <CODE>null</CODE> to this method will have no effect.
     * @param   o   the observer to be deleted.
     */
    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }

    /**
     * If this object has changed, as indicated by the
     * <code>hasChanged</code> method, then notify all of its observers
     * and then call the <code>clearChanged</code> method to
     * indicate that this object has no longer changed.
     * <p>
     * Each observer has its <code>update</code> method called with two
     * arguments: this observable object and <code>null</code>. In other
     * words, this method is equivalent to:
     * <blockquote><tt>
     * notifyObservers(null)</tt></blockquote>
     *
     * @see     java.util.Observable#clearChanged()
     * @see     java.util.Observable#hasChanged()
     * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
     */
    public void notifyObservers() {
        notifyObservers(null);
    }

    /**
     * If this object has changed, as indicated by the
     * <code>hasChanged</code> method, then notify all of its observers
     * and then call the <code>clearChanged</code> method to indicate
     * that this object has no longer changed.
     * <p>
     * Each observer has its <code>update</code> method called with two
     * arguments: this observable object and the <code>arg</code> argument.
     *
     * @param   arg   any object.
     * @see     java.util.Observable#clearChanged()
     * @see     java.util.Observable#hasChanged()
     * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
     */
    public void notifyObservers(Object arg) {
        /*
         * a temporary array buffer, used as a snapshot of the state of
         * current Observers.
         */
        Object[] arrLocal;

        synchronized (this) {
            /* We don't want the Observer doing callbacks into
             * arbitrary code while holding its own Monitor.
             * The code where we extract each Observable from
             * the Vector and store the state of the Observer
             * needs synchronization, but notifying observers
             * does not (should not).  The worst result of any
             * potential race-condition here is that:
             * 1) a newly-added Observer will miss a
             *   notification in progress
             * 2) a recently unregistered Observer will be
             *   wrongly notified when it doesn't care
             */
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }

    /**
     * Clears the observer list so that this object no longer has any observers.
     */
    public synchronized void deleteObservers() {
        obs.removeAllElements();
    }

    /**
     * Marks this <tt>Observable</tt> object as having been changed; the
     * <tt>hasChanged</tt> method will now return <tt>true</tt>.
     */
    protected synchronized void setChanged() {
        changed = true;
    }

    /**
     * Indicates that this object has no longer changed, or that it has
     * already notified all of its observers of its most recent change,
     * so that the <tt>hasChanged</tt> method will now return <tt>false</tt>.
     * This method is called automatically by the
     * <code>notifyObservers</code> methods.
     *
     * @see     java.util.Observable#notifyObservers()
     * @see     java.util.Observable#notifyObservers(java.lang.Object)
     */
    protected synchronized void clearChanged() {
        changed = false;
    }

    /**
     * Tests if this object has changed.
     *
     * @return  <code>true</code> if and only if the <code>setChanged</code>
     *          method has been called more recently than the
     *          <code>clearChanged</code> method on this object;
     *          <code>false</code> otherwise.
     * @see     java.util.Observable#clearChanged()
     * @see     java.util.Observable#setChanged()
     */
    public synchronized boolean hasChanged() {
        return changed;
    }

    /**
     * Returns the number of observers of this <tt>Observable</tt> object.
     *
     * @return  the number of observers of this object.
     */
    public synchronized int countObservers() {
        return obs.size();
    }
}

  • java.util.Observer 觀察者
package java.util;

/**
 * A class can implement the <code>Observer</code> interface when it
 * wants to be informed of changes in observable objects.
 *
 * @author  Chris Warth
 * @see     java.util.Observable
 * @since   JDK1.0
 */
public interface Observer {
    /**
     * This method is called whenever the observed object is changed. An
     * application calls an <tt>Observable</tt> object's
     * <code>notifyObservers</code> method to have all the object's
     * observers notified of the change.
     *
     * @param   o     the observable object.
     * @param   arg   an argument passed to the <code>notifyObservers</code>
     *                 method.
     */
    void update(Observable o, Object arg);
}

由于代碼比較簡單,此處就不做解讀了拖吼。
下面我們來實(shí)現(xiàn)我們的需求

代碼結(jié)構(gòu)

被觀察者(Observable)和觀察者(Observer)之間是一對多的關(guān)系

  • WeixinPublic 被觀察者(發(fā)布者)
import java.util.Observable;

/**
 * @Author: ming.wang
 * @Date: 2019/3/7 10:46
 * @Description:
 */
@Getter
@Setter
@ToString
public class WeixinPublic extends Observable {

    private String name;

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

    public void publishNews(String content){
        System.out.println(name+"發(fā)布新消息來鳞上,內(nèi)容是:"+content+"。");
        setChanged();
        notifyObservers(content);
    }

}
  • ZhangSan 觀察者(訂閱者)
import java.util.Observable;
import java.util.Observer;

/**
 * @Author: ming.wang
 * @Date: 2019/3/7 10:46
 * @Description:
 */
@Getter
@Setter
@ToString
public class ZhangSan implements Observer {

    private String name;

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

    @Override
    public void update(Observable o, Object arg) {

        WeixinPublic weixinPublic= (WeixinPublic) o;
        String content= (String) arg;
        System.out.println(name+"吊档,您關(guān)注的"+weixinPublic.getName()+"有新的更新篙议,內(nèi)容是:"+content);

    }
}

  • Lisi 觀察者(訂閱者)
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.Observable;
import java.util.Observer;

/**
 * @Author: ming.wang
 * @Date: 2019/3/7 10:46
 * @Description:
 */
@Getter
@Setter
@ToString
public class Lisi implements Observer {

    private String name;

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

    @Override
    public void update(Observable o, Object arg) {

        WeixinPublic weixinPublic= (WeixinPublic) o;
        String content= (String) arg;
        System.out.println(name+",您關(guān)注的"+weixinPublic.getName()+"有新的更新怠硼,內(nèi)容是:"+content);

    }
}

  • Test
/**
 * @Author: ming.wang
 * @Date: 2019/3/7 11:02
 * @Description:
 */
public class Test {
    public static void main(String[] args) {
        WeixinPublic weixinPublic=new WeixinPublic("技術(shù)狂奔路");
        weixinPublic.addObserver(new ZhangSan("張三"));
        weixinPublic.addObserver(new Lisi("李四"));
        weixinPublic.publishNews("java設(shè)計(jì)模式該怎么學(xué)鬼贱?");
    }
}

運(yùn)行結(jié)果

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市香璃,隨后出現(xiàn)的幾起案子这难,更是在濱河造成了極大的恐慌,老刑警劉巖葡秒,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姻乓,死亡現(xiàn)場離奇詭異嵌溢,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蹋岩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門赖草,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人剪个,你說我怎么就攤上這事秧骑。” “怎么了扣囊?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵乎折,是天一觀的道長。 經(jīng)常有香客問我侵歇,道長笆檀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任盒至,我火速辦了婚禮酗洒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘枷遂。我一直安慰自己樱衷,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布酒唉。 她就那樣靜靜地躺著矩桂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪痪伦。 梳的紋絲不亂的頭發(fā)上侄榴,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機(jī)與錄音网沾,去河邊找鬼癞蚕。 笑死,一個(gè)胖子當(dāng)著我的面吹牛辉哥,可吹牛的內(nèi)容都是我干的桦山。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼醋旦,長吁一口氣:“原來是場噩夢啊……” “哼恒水!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起饲齐,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤钉凌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后捂人,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體御雕,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡矢沿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了饮笛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咨察。...
    茶點(diǎn)故事閱讀 39,841評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡论熙,死狀恐怖福青,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情脓诡,我是刑警寧澤无午,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站祝谚,受9級特大地震影響宪迟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜交惯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一次泽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧席爽,春花似錦意荤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至齐饮,卻和暖如春捐寥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背祖驱。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工握恳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人捺僻。 一個(gè)月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓睡互,卻偏偏與公主長得像,于是被迫代替她去往敵國和親陵像。 傳聞我的和親對象是個(gè)殘疾皇子就珠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容