一:观察者模式定义:

       目标和观察者是基类,目标提供维护观察者的一系列方法,观察者提供更新接口。具体观察者和具体目标继承各自的基类,然后具体观察者把自己注册到具体目标里,在具体目标发生变化时候,调度观察者的更新方法。简单来说,就是被观察对象发生改变时,会通知其他相关的状态发生变化。

 

 

二:观察者模式实例应用:

        下面是一个RSS阅读器和Mail阅读器读取博客和门户更新的案例。该案例中,bloger和portal是发布者,即被观察者(subject),RSS阅读器和Mail阅读器是观察者,当bloger和portal产生新内容时,会自动调度观察者的更新方法,使观察者RSS阅读器和Mail阅读器产生相应更新。

(1)下图为观察者模式的类图:

 

 

 

 

(2)项目代码:

①抽象被观察者:CObservable,它把所有观察者对象的引用保存到一个聚集里,抽象主题提供一个接口,可以增加和删除观察者对象。

//被观察者,即Subject
class CObservable
{
public:
    CObservable() : m_bChanged(false) {};
    virtual ~CObservable() {};
    void Attach(CObserver* pObs);   //注册观察者
    void Detach(CObserver* pObs);   //注销观察者
    void DetachAll();               //注销所有观察者
    void Notify(void* pArg = NULL); //若状态变化,则遍历观察者,逐个通知更新
    bool HasChanged();              //测试目标状态是否变化
    int GetObserversCount();        //获取观察者数量
protected:
    void SetChanged();              //设置状态变化!!!必须继承CObservable才能设置目标状态
    void ClearChanged();            //初始化目标为未变化状态
private:
    bool m_bChanged;                //状态
    set<CObserver*> m_setObs;       //set保证目标唯一性
};

②具体被观察者角色:CBloger和CPortal,也就是一个具体的主题,内部状态改变时,对所有登记过的观察者RSS阅读器和Mail阅读器发出通知。

/////////////////////具体应用类定义和实现
//bloger是发布者,即被观察者(subject)
class CBloger : public CObservable
{
public:
    void Publish(const string &strContent) {
        cout << "bloger publish, content: " << strContent << endl;
        SetChanged();
        Notify(const_cast<char*>(strContent.c_str()));
    }
};

//portal是发布者,即被观察者(subject)
class CPortal : public CObservable
{
public:
    void Publish(const string &strContent) {
        cout << "portal publish, content: " << strContent << endl;
        SetChanged();
        Notify(const_cast<char*>(strContent.c_str()));
    }
};

③抽象观察者角色:CObserver,为所有的具体观察者定义一个接口,在得到被观察者通知之会更新自己。

/////////////////////抽象模式定义
class CObservable;
//观察者,纯虚基类
class CObserver
{
public:
    CObserver() {};
    virtual ~CObserver() {};
    //当被观察的目标发生变化时,通知调用该方法
    //来自被观察者pObs, 扩展参数为pArg
    virtual void Update(CObservable* pObs, void* pArg = NULL) = 0;
};

 

④具体观察者角色:CRSSReader和CMailReader,实现抽象观察者角色所需要的更新接口。

//RSS阅读器,观察者
class CRSSReader : public CObserver
{
public:
    CRSSReader(const string &strName) : m_strName(strName) {}
    virtual void Update(CObservable* pObs, void* pArg = NULL) {
        char* pContent = static_cast<char*>(pArg);
        //观察多个目标
        if (dynamic_cast<CBloger*>(pObs)) {
            cout << m_strName << " updated from bloger, content: " << pContent << endl;
        }
        else if (dynamic_cast<CPortal*>(pObs)) {
            cout << m_strName << " updated from portal, content: " << pContent << endl;
        }
    }
private:
    string m_strName;
};

//Mail阅读器,观察者
class CMailReader : public CObserver
{
public:
    CMailReader(const string &strName) : m_strName(strName) {}
    virtual void Update(CObservable* pObs, void* pArg = NULL) {
        char* pContent = static_cast<char*>(pArg);
        if (dynamic_cast<CBloger*>(pObs)) {
            cout << m_strName << " updated from bloger, content: " << pContent << endl;
        }
        if (dynamic_cast<CPortal*>(pObs)) {
            cout << m_strName << " updated from portal, content: " << pContent << endl;
        }
    }
private:
    string m_strName;
};

使用观察者模式后,RSS阅读器和Mail阅读器会自动得到bloger和portal的更新,从而使用户能够知道bloger和portal产生了变化。

 

三:优缺点分析:

优点: (1)、观察者和被观察者是抽象耦合的。这是一种高内聚低耦合的软件设计模式 (2)、建立一套触发机制。

(3)观察者模式满足“开闭原则”的要求,增加新的具体观察者无须修改原有系统代码,在具体观察者与观察目标之间不存在关联关系的情况下,增加新的观察目标也很方便。

 

缺点: (1)、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。

(2)、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。

(3)、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

 

四:代码地址:https://github.com/seabeach000/stdFuture/blob/ec7920337c0e387edca76a72b7a33d6d97fb9f99/observer/Observable.h

参考资料:http://www.cnblogs.com/lovesong/p/5272752.html