設(shè)計(jì)模式[15]-觀察者模式-Observer Pattern

1.觀察者模式簡(jiǎn)介

觀察者模式(Observer Pattern)是行為型(Behavioral)設(shè)計(jì)模式茧痒,定義了對(duì)象之間一對(duì)多的依賴關(guān)系带膜,當(dāng)一個(gè)對(duì)象發(fā)生狀態(tài)變更,所有的依賴對(duì)象都會(huì)被通知苍在。在觀察者模式中闻葵,發(fā)生變化的對(duì)象就是觀察目標(biāo)情龄,被通知的對(duì)象就是觀察者伐割,觀察目標(biāo)和觀察者是一對(duì)多的關(guān)系。

觀察者模式又被稱作發(fā)布/訂閱(Pub/Sub)模式刃唤。

觀察者模式一共有四種角色:

(1) Subject(主題):是觀察的目標(biāo)隔心,可以是接口或者抽象類,定義了增加尚胞、移除硬霍、通知觀察者的方法,還有自身操作的方法笼裳。

(2) ConcreteSubject(具體主題):具體主題是Subject的子類唯卖,內(nèi)部維護(hù)者具體有哪些觀察者;當(dāng)它的狀態(tài)發(fā)生改變時(shí)躬柬,向它的各個(gè)觀察者發(fā)出通知拜轨。有時(shí)候,Subject可以和ConcreteSubject合并成一個(gè)類允青。

(3)Observer(觀察者):觀察者將對(duì)觀察目標(biāo)的改變做出反應(yīng)橄碾,觀察者一般定義為接口,該接口聲明了更新數(shù)據(jù)的方法颠锉。

(4)ConcreteObserver(具體觀察者):具體觀察者實(shí)現(xiàn)抽象觀察者定義的方法法牲,完成具體的更新數(shù)據(jù)的動(dòng)作。

2. 觀察者模式舉例

下面舉個(gè)例子琼掠,當(dāng)股票股價(jià)小于10元或者大約20元時(shí)拒垃,向關(guān)注股票的股民(Investor)發(fā)送通知消息。

序號(hào) 類名 角色 說明
1 Observer Observer 抽象觀察者
2 Investor ConcreteSubject 股民類瓷蛙,具體觀察者角色
3 Subject Subject 抽象主題悼瓮,是被觀察的對(duì)象
4 Stock ConcreteObserver 股票類,具體主題角色
5 ObserverMain 客戶端 演示調(diào)用
Paste_Image.png

1. 抽象觀察者

/**
 * 抽象觀察者
 */
public interface Observer {

    void update(String message);
}

2. 股民類艰猬,具體觀察者角色

/**
 * 股民類横堡,具體觀察者角色
 */
public class Investor implements Observer {

    private String name;

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

    @Override
    public void update(String message) {
        System.out.println("股民[" + name + "]收到了消息:" + message);
    }
}

3.抽象主題,是被觀察的對(duì)象姥宝。

/**
 * 抽象主題翅萤,是被觀察的對(duì)象。
 */
public interface Subject {

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

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

    /**
     * 通知觀察者
     *
     * @param message 消息
     */
    void notifyObservers(String message);

    /**
     * 模擬股票價(jià)格監(jiān)控
     *
     * @param price 股票價(jià)格
     */
    void change(int price);

}

4.股票類腊满,具體主題角色

/**
 * 股票類套么,具體主題角色
 */
public class Stock implements Subject {

    private Vector<Observer> observers = new Vector<>();

    /**
     * 模擬股票價(jià)格監(jiān)控
     *
     * @param price 股票價(jià)格
     */
    public void change(int price) {
        if (price > 2000) {
            notifyObservers("股票價(jià)格已經(jīng)超過20元。");
        } else if (price < 1000) {
            notifyObservers("股票價(jià)格已經(jīng)低于10元碳蛋。");
        }
    }

    /**
     * 增加觀察者
     *
     * @param observer
     */
    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    /**
     * 刪除觀察者
     *
     * @param observer
     */
    @Override
    public void deleteObserver(Observer observer) {
        observers.remove(observer);
    }

    /**
     * 通知觀察者
     *
     * @param message 消息
     */
    @Override
    public void notifyObservers(String message) {
        Enumeration<Observer> enumeration = observers.elements();
        while (enumeration.hasMoreElements()) {
            Observer observer = enumeration.nextElement();
            observer.update(message);
        }
    }
}

5.調(diào)用演示

public static void main(String[] args) {
    // 創(chuàng)建觀察者對(duì)象
    Observer observer1 = new Investor("張三");
    Observer observer2 = new Investor("李四");
    // 注冊(cè)觀察者對(duì)象
    Subject stock = new Stock();
    stock.addObserver(observer1);
    stock.addObserver(observer2);
    // stock 主題發(fā)生的變化胚泌,觀察者收到通知
    stock.change(2100);
    stock.change(900);
}

結(jié)果輸出:

股民[張三]收到了消息:股票價(jià)格已經(jīng)超過20元。
股民[李四]收到了消息:股票價(jià)格已經(jīng)超過20元肃弟。
股民[張三]收到了消息:股票價(jià)格已經(jīng)低于10元玷室。
股民[李四]收到了消息:股票價(jià)格已經(jīng)低于10元。

3. 總結(jié)

觀察者模式是一個(gè)使用頻率很高的設(shè)計(jì)模式笤受,為對(duì)象之間的行為聯(lián)動(dòng)提供了一套方案穷缤,簡(jiǎn)化了一對(duì)多的系統(tǒng)設(shè)計(jì)難度;需要注意的是箩兽,我們應(yīng)該避免觀察者和觀察目標(biāo)之間循環(huán)依賴津肛。

有的同學(xué)曾經(jīng)討論觀察者模式和“發(fā)布/訂閱”模式之間的區(qū)別,提出一種觀點(diǎn):在觀察者模式中汗贫,觀察目標(biāo)(本例中的Subject身坐、Stock)直接依賴觀察者(本例中的Observer);而“發(fā)布/訂閱”模式中落包,觀察目標(biāo)并不直接依賴于觀察者部蛇,而是通過中介媒介來通信。

在消息隊(duì)列中間件或者說JMS協(xié)議中咐蝇,Topic就是“發(fā)布/訂閱”的模式涯鲁,發(fā)布消息的生產(chǎn)者把消息送入Topic,消費(fèi)消息的消費(fèi)者訂閱這個(gè)Topic有序,從中消費(fèi)數(shù)據(jù)撮竿;生產(chǎn)者和消費(fèi)者互不依賴。

(完)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末笔呀,一起剝皮案震驚了整個(gè)濱河市幢踏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌许师,老刑警劉巖房蝉,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異微渠,居然都是意外死亡搭幻,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門逞盆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來檀蹋,“玉大人,你說我怎么就攤上這事云芦「┯猓” “怎么了贸桶?”我有些...
    開封第一講書人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)桌肴。 經(jīng)常有香客問我皇筛,道長(zhǎng),這世上最難降的妖魔是什么坠七? 我笑而不...
    開封第一講書人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任水醋,我火速辦了婚禮,結(jié)果婚禮上彪置,老公的妹妹穿的比我還像新娘拄踪。我一直安慰自己,他們只是感情好拳魁,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開白布惶桐。 她就那樣靜靜地躺著,像睡著了一般的猛。 火紅的嫁衣襯著肌膚如雪耀盗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,328評(píng)論 1 310
  • 那天卦尊,我揣著相機(jī)與錄音叛拷,去河邊找鬼。 笑死岂却,一個(gè)胖子當(dāng)著我的面吹牛忿薇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播躏哩,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼署浩,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了扫尺?” 一聲冷哼從身側(cè)響起筋栋,我...
    開封第一講書人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎正驻,沒想到半個(gè)月后弊攘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡姑曙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年襟交,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伤靠。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡捣域,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情焕梅,我是刑警寧澤迹鹅,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站丘侠,受9級(jí)特大地震影響徒欣,放射性物質(zhì)發(fā)生泄漏逐样。R本人自食惡果不足惜蜗字,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望脂新。 院中可真熱鬧挪捕,春花似錦、人聲如沸争便。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽滞乙。三九已至奏纪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間斩启,已是汗流浹背序调。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留兔簇,地道東北人发绢。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像垄琐,于是被迫代替她去往敵國和親边酒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

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