观察者模式(C++版)

情景介绍

假如现在有一份数据,是一个班级每天的出勤人数,在程序中我们需要用不同的方式去显示这份数据(比如折线图,柱状图等)。同时,当数据被改变的时候,所有以该数据为基础的图也要进行更新,在这种情境中,观察者模式是一个很好的选择。
换个例子,想想报纸和杂志的订阅过程:

  1. 报社的业务就是出版报纸;
  2. 当向某家报社订阅报纸,只要报社有新报纸出版,就会给你送来。只要你是他们的订户,就会一直受到新报纸;
  3. 当不再想要这家报社的报纸的时候,取消订阅,他们就不会再送新报纸;
  4. 只要报社还在运营,就会一直有人向他们订阅或取消订阅报纸;

出版者(主题/报社)+订阅者(观察者/人)= 观察者模式

代码详情

由上述可知,观察者模式应有两部分:被观察者和观察者!有种听君一席话,如听一席话的感觉(bushi)
闲话少说,上代码!

被观察者

首先,是被观察者的接口:

    /**
     * 被观察者 主题
     */
    class Subject {
    public:
    	//注册(订阅)
        virtual void registerObserver(const std::shared_ptr<Observer> &observer) = 0;

		//移除(取关)
        virtual void removeObserver(const std::shared_ptr<Observer> &observer) = 0;
		
		//通知观察者它们观察的东西改变啦
        virtual void notifyObservers() = 0;

        virtual ~Subject() = default;
    };

其次,是一个实际的被观察者:

class WeatherData : public Subject {
    public:
        WeatherData(float temp, float humidity, float pressure) : temp(temp), humidity(humidity), pressure(pressure) {};

		//注册
        void registerObserver(const std::shared_ptr<Observer> &observer) override {
            observerVector.push_back(observer);
        }
		//移除
        void removeObserver(const std::shared_ptr<Observer> &observer) override {
        	//这么写会不会有什么问题,不过测试的结果还是符合预期的
            auto target = std::find(observerVector.begin(), observerVector.end(), observer);
            if (target != observerVector.end()) {
                observerVector.erase(target);
            }
        }

        void notifyObservers() override {
            for (const auto &tmp: observerVector) {
            	//通知观察者应该更新啦
                tmp->update(temp, humidity, pressure);
            }
        }

        void measurementsChanged() {
            notifyObservers();
        }

        void setMeasurements(float temp, float humidity, float pressure) {
            this->temp = temp;
            this->humidity = humidity;
            this->pressure = pressure;
            measurementsChanged();
        }

        float getTemp() const {
            return temp;
        }

        float getHumidity() const {
            return humidity;
        }

        float getPressure() const {
            return pressure;
        }

    private:
        float temp{0.0};
        float humidity{0.0};
        float pressure{0.0};
        std::vector<std::shared_ptr<Observer>> observerVector;
    };

观察者

介绍完被观察者,现在可以介绍观察者了。首先是接口:

    /**
     * 观察者
     */
    class Observer {

    public:
    	//作为观察者,update方法是必要的,被观察者需要调用此方法
        virtual void update(float temp, float humidity, float pressure) = 0;

        virtual ~Observer() = default;
    };

在本例中,还用到了另一个接口,用于提供显示方法:

class DisplayElement {
    public:
        virtual void display() = 0;

        ~DisplayElement() = default;

    };

接下来实现:

    class CurrentConditionsDisplay : public Observer, public DisplayElement {
    public:
        CurrentConditionsDisplay() = default;

        void display() override {
            std::cout << "Current conditions: " << temperature
                      << "F degrees and " << humidity
                      << "% humidity" << std::endl;
        }

        void update(float temp, float humidity, float pressure) override {
            this->temperature = temp;
            this->humidity = humidity;
            display();
        }

    private:
        float temperature;
        float humidity;
    };


    class StatisticsDisplay : public Observer, public DisplayElement {
    public:
        StatisticsDisplay() = default;

        void display() override {
            std::cout << "Avg/Max/Min temperature = " << (tempSum / numReadings)
                      << "/" << maxTemp << "/" << minTemp << std::endl;
        }

        void update(float temp, float humidity, float pressure) override {
            tempSum += temp;
            numReadings++;

            if (temp > maxTemp) {
                maxTemp = temp;
            }

            if (temp < minTemp) {
                minTemp = temp;
            }

            display();
        }

    private:
        float maxTemp{0.0f};
        float minTemp{200};
        float tempSum{0.0f};
        int numReadings;
    };

也可以进行自定义实现哦。

示例

void observerTest() {
    Observer::WeatherData weatherData(0, 0, 0);

    std::shared_ptr<Observer::Observer> currentDisplay = std::make_shared<Observer::CurrentConditionsDisplay>();
    std::shared_ptr<Observer::Observer> forecast = std::make_shared<Observer::ForecastDisplay>();
    std::shared_ptr<Observer::Observer> heatDisplay = std::make_shared<Observer::HeatIndexDisplay>();
    std::shared_ptr<Observer::Observer> statistics = std::make_shared<Observer::StatisticsDisplay>();

    weatherData.registerObserver(currentDisplay);
    weatherData.registerObserver(forecast);
    weatherData.registerObserver(heatDisplay);
    weatherData.registerObserver(statistics);

    weatherData.setMeasurements(80, 65, 40.3f);
    weatherData.removeObserver(forecast);
    weatherData.setMeasurements(78, 90, 29.2f);
}

总结

观察者模式架构图如下:
观察者模式

观察者模式

观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新;

设计原则

  1. 为交互对象之间的松耦合设计而努力;
  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值