1. 观察者模式简介

观察者模式又叫做发布订阅模式,它是一种行为型模式。

假如我们要开发一款图表绘制程序,其中有一个环节就是根据最新的数据绘制饼图和折线图,并且当数据更新的时候,饼图和折线图能够及时地进行更新。

一般情况下我们会怎么做呢?我们的直接想法可能就是,每隔一段时间去检查一下,数据有没有更新。而且为了能够及时更新的图表,检查的时间间隔不能太长。那么检查的间隔时间太短又会浪费CPU的时间做无用功。

 这种每隔一会就检查一下的办法看起来就笨笨的,而且吃力不讨好,可能检查了好多遍数据都没有变。要是数据发生变化的时候能够自动通知我们就好了,等它来通知我们的时候,我们再去根据最新的数据进行图表的绘制。这样就能大大提高效率,减少无用的操作了。

很好!你已经发现了观察者模式!(或者说发布订阅模式)

这个模式涉及到了两种对象:主题对象(Subject)和观察者对象(Observer)。主题对象负责维护一个主题,这个主题可以是任何我们关心的数据。主题对象还会记录当前有哪些观察者对象订阅了该主题。当主题发生变化的时候,主题对象会自动通知这些观察者对象。

以上就是观察者模式的核心概念,下面通过一个简单的小栗子来看看到底是怎么回事。

2. 观察者模式的小栗子

依然以上面提到的图表绘制程序作为示例,代码如下:

#include <iostream>
#include <vector>

using namespace std;

class Observer;
class Subject {
public:
    virtual void attach(Observer* observer) = 0;
    virtual void detach(Observer* observer) = 0;
    virtual void notify() = 0;
};

class Observer {
public:
    virtual void update(const vector<int>& data) = 0;
};

class ConcreteSubject : public Subject {
private:
    vector<Observer*> observers;
    vector<int> data;
public:
    void attach(Observer* observer) {
        observers.push_back(observer);
    }
    void detach(Observer* observer) {
        observers.erase(remove(observers.begin(), observers.end(), observer), observers.end());
    }
    void notify() {
        for (auto observer : observers) {
            observer->update(data);
        }
    }
    void setData(const vector<int>& newData) {
        data = newData;
        notify();
    }
};

class PieGraphObserver : public Observer {
public:
    void update(const vector<int>& data) {
        cout << "使用数据绘制饼图:";
        for (auto num : data) {
            cout << num << " ";
        }
        cout << endl;
    }
};

class LineGraphObserver : public Observer {
public:
    void update(const vector<int>& data) {
        cout << "使用数据绘制折线图:";
        for (auto num : data) {
            cout << num << " ";
        }
        cout << endl;
    }
};

int main() {
    
    ConcreteSubject* subject = new ConcreteSubject();
    Observer* pieObserver = new PieGraphObserver();
    Observer* lineObserver = new LineGraphObserver();

    subject->attach(pieObserver);
    subject->attach(lineObserver);

    cout << "---------------" << endl;
    cout << "数据更新为: 1 2 3" << endl;
    vector<int> data1 = { 1, 2, 3 };
    subject->setData(data1);

    cout << endl << endl;
    cout << "---------------" << endl;
    cout << "数据更新为: 4 5 6" << endl;
    vector<int> data2 = { 4, 5, 6 };
    subject->setData(data2);

    cout << "lineObserver 注销观察" << endl;
    subject->detach(lineObserver);

    cout << endl << endl;
    cout << "---------------" << endl;
    cout << "数据更新为: 4 5 6" << endl;
    vector<int> data3 = { 7, 8, 9 };
    subject->setData(data3);

    delete subject;
    delete pieObserver;
    delete lineObserver;

    return 0;
}

其中,Observer类就是我们的抽象观察者类,Subject就是我们的抽象主题类。提供了attach用来添加观察者,detach用来注销观察者,notify用来通知观察者。

PieGraphOvserver是具体的饼图观察者类,用来绘制饼图。

LineGraphObserver是具体的折线图观察者类,用来绘制折线图。

ConcreteSubject是具体的主题类,通过vector维护了对主题进行观察的观察者,以及当前的数据。可以通过setData来更新数据。

当我们使用setData来更新数据时,就会自动调用notify来通知所有的观察者,并把最新的数据交给他们,他们各自也会通过他们的手段来更新图表。

以上就是观察者模式的讲解,感谢大家看到这里,写的不严谨,敬请批评指正。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐