C++ 常用设计模式学习——观察者模式

观察者模式(Observer),又叫发布-订阅模式(Publish/Subscribe):定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都要得到通知并自动更新。

观察者模式从根本上讲必须包含两个角色:观察者和被观察对象。

  • 被观察对象自身应该包含一个容器来存放观察者对象,当被观察者自身发生改变时通知容器内所有的观察者对象自动更新。

  • 观察者对象可以注册到被观察者的中,完成注册后可以检测被观察者的变化,接收被观察者的通知。当然观察者也可以被注销掉,停止对被观察者的监控。

Subject(目标)

  目标知道它的观察者。可以有任意多个观察者观察同一个目标;

  提供注册和删除观察者对象的接口。

Observer(观察者)

  为那些在目标发生改变时需获得通知的对象定义一个更新接口。

ConcreteSubject(具体目标)

  将有关状态存入各ConcreteObserver对象;

  当它的状态发生改变时,向它的各个观察者发出通知。

ConcreteObserver(具体观察者)

  维护一个指向ConcreteSubject对象的引用;

  存储有关状态,这些状态应与目标的状态保持一致;

  实现Observer的更新接口以使自身状态与目标的状态保持一致。

观察者模式按照以下方式进行协作:

  1)当ConcreteSubject发生任何可能导致其观察者与其本身状态不一致的改变时,它将通知它的各个观察者;

  2)在得到一个具体目标的改变通知后,ConcreteObserver对象可向目标对象查询信息。ConcreteObserver使用这些信息以使它的状态与目标对象的状态一致。

适用场合:

  1)当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立的改变和复用;

  2)当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变;

  3)当一个对象必须通知其它对象,而它又不能假定其它对象是谁;也就是说,你不希望这些对象是紧密耦合的。

/*
* 关键代码:在目标类中增加一个ArrayList来存放观察者们。
*/
#include <iostream>
#include <list>
#include <memory>using namespace std;
​
class View;
​
//被观察者抽象类   数据模型
class DataModel
{
public:
    virtual ~DataModel(){}
    virtual void addView(View* view) = 0;
    virtual void removeView(View* view) = 0;
    virtual void notify() = 0;   //通知函数
};
​
//观察者抽象类   视图
class View
{
public:
    virtual ~View(){ cout << "~View()" << endl; }
    virtual void update() = 0;
    virtual void setViewName(const string& name) = 0;
    virtual const string& name() = 0;
};
​
//具体的被观察类, 整数模型
class IntDataModel:public DataModel
{
public:
    ~IntDataModel()
    {
        m_pViewList.clear();
    }
​
    virtual void addView(View* view) override
    {
        shared_ptr<View> temp(view);
        auto iter = find(m_pViewList.begin(), m_pViewList.end(), temp);
        if(iter == m_pViewList.end())
        {
            m_pViewList.push_front(temp);
        }
        else
        {
            cout << "View already exists" << endl;
        }
    }
​
    void removeView(View* view) override
    {
        auto iter = m_pViewList.begin();
        for(; iter != m_pViewList.end(); iter++)
        {
            if((*iter).get() == view)
            {
                m_pViewList.erase(iter);
                cout << "remove view" << endl;
                return;
            }
        }
    }
​
    virtual void notify() override
    {
        auto iter = m_pViewList.begin();
        for(; iter != m_pViewList.end(); iter++)
        {
            (*iter).get()->update();
        }
    }
​
private:
    list<shared_ptr<View>> m_pViewList;
};
​
//具体的观察者类    表视图
class TableView : public View
{
public:
    TableView() : m_name("unknow"){}
    TableView(const string& name) : m_name(name){}
    ~TableView(){ cout << "~TableView(): " << m_name.data() << endl; }
​
    void setViewName(const string& name)
    {
        m_name = name;
    }
​
    const string& name()
    {
        return m_name;
    }
​
    void update() override
    {
        cout << m_name.data() << " update" << endl;
    }
​
private:
    string m_name;
};
​
int main()
{
    /*
    * 这里需要补充说明的是在此示例代码中,View一旦被注册到DataModel类之后,DataModel解析时会自动解析掉     * 内部容器中存储的View对象,因此注册后的View对象不需要在手动去delete,再去delete View对象会出错。
    */

    View* v1 = new TableView("TableView1");
    View* v2 = new TableView("TableView2");
    View* v3 = new TableView("TableView3");
    View* v4 = new TableView("TableView4");
​
    IntDataModel* model = new IntDataModel;
    model->addView(v1);
    model->addView(v2);
    model->addView(v3);
    model->addView(v4);
​
    model->notify();
​
    cout << "-------------\n" << endl;
​
    model->removeView(v1);
​
    model->notify();
​
    delete model;
    model = nullptr;
​
    return 0;
}

 

posted @ 2021-08-08 22:40  Jcpeng_std  阅读(331)  评论(0编辑  收藏  举报