設計模式之 觀察者模式(Publish/Subscribe)模式

介紹

觀察者模式定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一個主題對象。 這個主題對象在狀態發生變化時,會通知所有觀察者對象,使它們能夠自動更新自己。[DP]

  • Subject被觀察者
    定義被觀察者必須實現的職責,它必須能夠動態地增加、取消觀察者。它一般是抽象類或者是實現類,僅僅完成作爲被觀察者必須實現的職責:管理觀察者並通知觀察者。
  • Observer觀察者
    觀察者接收到消息後,即進行update(更新方法)操作,對接收到的信息進行處理。
  • ConcreteSubject具體的被觀察者
    定義被觀察者自己的業務邏輯,同時定義對哪些事件進行通知。
  • ConcreteObserver具體的觀察者
    每個觀察在接收到消息後的處理反應是不同,各個觀察者有自己的處理邏輯。

優點:觀察者和被觀察者之間是抽象耦合;建立一套觸發機制

應用:關聯行爲場景。需要注意的是,關聯行爲是可拆分的,而不是組合關係;事件多級觸發場景;跨系統的消息交換場景,如消息隊列的處理機制

注意:廣播連,消息最多轉發一次(傳遞兩次)

 

UML類圖

簡單示例代碼:

#ifndef SIMPLE_OBSERVER_H
#define SIMPLE_OBSERVER_H

#include <iostream>
#include <list>
#include <string>

using namespace std;

/**
 * @brief The Observer class
 * 抽象觀察者,爲所有的具體觀察者定義一個接口,在得到主題的通知時更新自己。
 * 抽象觀察者一般用一個抽象類或者一個接口實現,通常包含一個Update()方法
 */
class Observer
{
public:
    virtual void update()
    {
        cout<<"Observer::update()"<<endl;
    }
};

/**
 * @brief The Subject class
 * 抽象通知者,它把所有對觀察者對象的引用保存在一個聚集裏
 */
class Subject
{
public:
    void attach(Observer *ob)
    {
        m_observers.push_back(ob);
    }

    void detach(Observer *ob)
    {
        m_observers.remove(ob);
    }

    void notify()
    {
        for (list<Observer *>::iterator it = m_observers.begin(); it != m_observers.end() ;it++) {
            (*it)->update();
        }
    }

private:
    list<Observer *> m_observers;
};

/**
 * @brief The ConcreteSubject class
 * 具體通知者
 */
class ConcreteSubject : public Subject
{
public:
    //具體被觀察者的狀態
    string getSubjectState()
    {
        return m_subjectState;
    }
    void setSubjectState(string stateStr)
    {
        m_subjectState = stateStr;
    }

private:
    string m_subjectState;
};

/**
 * @brief The ConcreteObserver class
 * 具體觀察者
 */
class ConcreteObserver : public Observer
{
public:
    ConcreteObserver(ConcreteSubject *subject , string name)
    {
        m_subject = subject;
        m_name = name;
    }

    void update()
    {
        m_observerState = m_subject->getSubjectState();
        cout<<"觀察者:"<<m_name<<"的狀態是:"<<m_observerState<<endl;
    }


private:
    string m_name ;
    string m_observerState;
    ConcreteSubject *m_subject;
};


#endif // SIMPLE_OBSERVER_H

調用代碼:

    ConcreteSubject *s = new ConcreteSubject;
    s->attach(new ConcreteObserver(s , "X"));
    s->attach(new ConcreteObserver(s , "Y"));
    s->attach(new ConcreteObserver(s , "Z"));

    s->setSubjectState("ABC");

    s->notify();

    s->setSubjectState("BCD");

    s->notify();

    delete  s;
    s = nullptr;

《大話設計模式種,公司前臺場景代碼》

#ifndef COMPANY_OBSERVER_H
#define COMPANY_OBSERVER_H

#include <iostream>
#include <list>
#include <string>

using namespace std;

class Subject;
/**
 * @brief The Observer class
 * 抽象觀察者,爲所有的具體觀察者定義一個接口,在得到主題的通知時更新自己。
 * 抽象觀察者一般用一個抽象類或者一個接口實現,通常包含一個Update()方法.
 *
 * 創建該觀察者同時,提供一個抽象通知者,因爲此時通知者有可能會變。
 */
class Observer
{
public:

    Observer(Subject *sub , string name)
    {
        m_subject = sub;
        m_name = name;
    }
    virtual void update()
    {
        cout<<"Observer::update()"<<endl;
    }

protected:
    string m_name ;
    Subject *m_subject;
};


/**
 * @brief The Subject class
 * 抽象通知者,它把所有對觀察者對象的引用保存在一個聚集裏
 * 因爲此時的通知者不知是:前臺  還是   老闆
 */
class Subject
{
public:
    void virtual attach(Observer *ob) = 0;
    void virtual detach(Observer *ob) = 0;
    void virtual  notify() = 0;
    void virtual setAction(string act) = 0;
    string virtual getAction() const = 0;

};

/***********************************具體的通知者*****************************************/

/**
 * @brief The Boss class
 * 具體的通知者:老闆自己回來了,前臺美女不在
 */
class Boss : public Subject
{
public:
    void attach(Observer *ob)
    {
        m_observers.push_back(ob);
    }

    void detach(Observer *ob)
    {
        m_observers.remove(ob);
    }

    void notify()
    {
        for (list<Observer *>::iterator it = m_observers.begin(); it != m_observers.end() ;it++) {
            (*it)->update();
        }
    }

    void setAction(string act)
    {
        m_action = act;
    }

    string getAction() const
    {
        return m_action;
    }

private:
    list<Observer *> m_observers;
    string m_action;
};

/**
 * @brief The Secretary class
 * 具體的通知者:老闆回來了,前臺美女在
 */
class Secretary : public Subject
{
public:
    void attach(Observer *ob)
    {
        m_observers.push_back(ob);
    }

    void detach(Observer *ob)
    {
        m_observers.remove(ob);
    }

    void notify()
    {
        for (list<Observer *>::iterator it = m_observers.begin(); it != m_observers.end() ;it++) {
            (*it)->update();
        }
    }

    void setAction(string act)
    {
        m_action = act;
    }

    string getAction() const
    {
        return m_action;
    }

private:
    list<Observer *> m_observers;
    string m_action;
};


/***********************************具體的觀察者******************************************/

/**
 * @brief The StockObserver class
 * 具體的觀察者:看股票的同事
 */
class StockObserver : public Observer
{
public:
    StockObserver(Subject *sub , string name )
        :Observer(sub , name)
    {

    }

    void update() override
    {
        cout<<m_subject->getAction()<<"   "<<m_name<<"  關閉股票軟件,繼續工作。\n";
    }
};

/**
 * @brief The GameObserver class
 * 具體的觀察者:玩遊戲的同事
 */
class GameObserver : public Observer
{
public:
    GameObserver(Subject *sub , string name )
        :Observer(sub , name)
    {

    }

    void update() override
    {
        cout<<m_subject->getAction()<<"   "<<m_name<<"  停止玩遊戲,繼續工作。\n";
    }
};

/**
 * @brief The NBAObserver class
 * 具體的觀察者:看NBA的同事
 */
class NBAObserver : public Observer
{
public:
    NBAObserver(Subject *sub , string name )
        :Observer(sub , name)
    {

    }

    void update() override
    {
        cout<<m_subject->getAction()<<"   "<<m_name<<"  停止觀看NBA,繼續工作。\n";
    }
};



#endif // COMPANY_OBSERVER_H

調用代碼:

    /*
    //具體的通知者
    Boss *pHuhansan = new Boss;

    //老闆回來,前臺不在

    //看股票的同事
    StockObserver *pSo = new StockObserver( pHuhansan , "易小天");

    //看NBA的同事
    NBAObserver *pNo = new NBAObserver(pHuhansan , "趙高");

    //玩遊戲的同事
    GameObserver *pGo = new GameObserver(pHuhansan , "項羽");

    //老闆添加觀察者
    pHuhansan->attach(pSo);
    pHuhansan->attach(pNo);
    pHuhansan->attach(pGo);

    pHuhansan->setAction("胡漢三我回來了");

    pHuhansan->notify();
    */

    //老闆回來,前臺在
    Secretary *pMeimei = new  Secretary;

    //看股票的同事
    StockObserver *pSo = new StockObserver( pMeimei , "易小天");

    //看NBA的同事
    NBAObserver *pNo = new NBAObserver(pMeimei , "趙高");

    //玩遊戲的同事
    GameObserver *pGo = new GameObserver(pMeimei , "項羽");

    //前臺添加觀察者,關係不好的不讓加
    pMeimei->attach(pSo);
    pMeimei->attach(pNo);
    pMeimei->attach(pGo);

    pMeimei->setAction("胡漢三大佬回來啦啦啦~~~");

    pMeimei->notify();

 

隨着對該模式理解的深入,會隨時更新該篇博客。

 

部分內容摘自網絡,若有侵權,聯繫刪除。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章