小話設計模式三:發布/訂閱模式


發布/訂閱模式定義:

  又稱為觀察者模式,定義對象間的一種一對多的依賴關系,一個發布者可以對應多個訂閱者,當發布者發生變化的時候,他可以將消息一一通知給所有的訂閱者當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。

發布/訂閱模式解析:

  UML圖如下,這里發布者IPublisher提供依賴於它的訂閱者的添加add和刪除remove操作,同時提供一個依賴於它的所有訂閱者同步的操作notify。訂閱者需要提供一個update操作,當發布者發出notify通知所有訂閱者時,進行調用update。                           

  簡單代碼示例如下:

//訂閱者基類
class ISubscriber
{
public:
    ISubscriber(string name);
    virtual void update(string strMsg) = 0;  //更新訂閱者自身狀態,由發布者調用
    virtual ~ISubscriber(){};
protected:
    string m_name;    //訂閱者名稱
};

ISubscriber::ISubscriber(string name) : m_name(name)
{
}

//發布者基類
class IPublisher
{
public:
    virtual void add(ISubscriber *pObserver) = 0;    //增加訂閱者
    virtual void remove(ISubscriber *pObserver) = 0; //移除訂閱者
    virtual void notify() = 0;                       //通知訂閱者
    virtual ~IPublisher(){};
    void setMsg(string strMsg);
    string getMsg();
protected:
    std::list<ISubscriber*> m_listObserver;          //保存所有訂閱者的列表
    string m_strMsg;                                 //發布者發布的消息
};

void IPublisher::setMsg(string strMsg)
{
    m_strMsg = strMsg;
}

string IPublisher::getMsg()
{
    return m_strMsg;
}

//發布者的實現類
class PublisherImpl : public IPublisher
{
public:
    virtual void add(ISubscriber *pObserver);
    virtual void remove(ISubscriber *pObserver);
    virtual void notify();
    ~PublisherImpl();

};

void PublisherImpl::add(ISubscriber *pObserver)
{
    std::list<ISubscriber*>::iterator iter = find(m_listObserver.begin(), m_listObserver.end(), pObserver);
    if (iter == m_listObserver.end())
    {
        m_listObserver.push_back(pObserver);
    }
}

void PublisherImpl::remove(ISubscriber *pObserver)
{
    std::list<ISubscriber*>::iterator iter = find(m_listObserver.begin(), m_listObserver.end(), pObserver);
    if (iter != m_listObserver.end())
    {
        m_listObserver.erase(iter);
    }
}

void PublisherImpl::notify()
{
    std::list<ISubscriber*>::iterator iter;
    for (iter = m_listObserver.begin(); iter != m_listObserver.end(); ++iter)
    {
        (*iter)->update(m_strMsg);
    }
}

PublisherImpl::~PublisherImpl()
{
    std::list<ISubscriber*>::iterator iter, temp;
    for (iter = m_listObserver.begin(); iter != m_listObserver.end(); ++iter)
    {
        temp = iter;
        delete (*temp);
    }
    m_listObserver.clear();
}

//訂閱者的實現類一
class CSDNSubscriber : public ISubscriber
{
public:
    CSDNSubscriber(string name);
    virtual void update(string strMsg);
};

CSDNSubscriber::CSDNSubscriber(string name) : ISubscriber(name)
{
}

void CSDNSubscriber::update(string strMsg)
{
    cout<<strMsg<<", 請關閉CSDN,停止上網,開始認真工作!"<<endl;
}

//訂閱者的實現類二
class ChatSubscriber : public ISubscriber
{
public:
    ChatSubscriber(string name);
    virtual void update(string strMsg);
};

ChatSubscriber::ChatSubscriber(string name) : ISubscriber(name)
{
}

void ChatSubscriber::update(string strMsg)
{
    cout<<strMsg<<", 請停止聊天,開始認真工作!"<<endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
    IPublisher *pSubject = new PublisherImpl;
    ISubscriber *pSubscriber = NULL;
    pSubscriber = new CSDNSubscriber("張三");  //向發布者中注冊訂閱者
    pSubject->add(pSubscriber);
    pSubscriber = new ChatSubscriber("李四");
    pSubject->add(pSubscriber);
    pSubscriber = new ChatSubscriber("王五");
    pSubject->add(pSubscriber);
    pSubject->setMsg("主管回來了");
    pSubject->notify();                    //發布者通知所有訂閱者
return 0; }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM