【HeadFirst 设计模式】观察者模式的C++实现

一、案例背景

贵公司获选为我公司建立下一代Internet气象观测站! 该气象站必须建立在我们专利申请中的WeatherData对象上,由WeatherData对象负责追踪目前的天气状况 (温度、 湿度、气压)。

我们希望贵公司能建立一个应用,有三种布告板,分别显示目前的状况、气象统计及简单的预报。 当WeatherObject对象获得最新的测量数据时, 三种布告板 必须实时更新。 而且,这是一个可以扩展的气象站,Weather -0-Rama气象 站希望公布 一组API,好让其他开发人员可以写出自己的 气象布告板,并插入此应用中。我们希望贵公司能提供这样的API。

二、案例分析

这是一种很常见的场景。WeatherObject对象相当于一个主题,管理了三个对象:温度、 湿度、气压。三种布告板需要订阅这个主题,以便拿到最新的数据并显示。

实现这些并不难,难的是你要未雨绸缪般预料到将来你的工作将会发生什么样的变化,好让自己在这些变化来临时,快速的去响应变化,从而少加点班。

你的工作是为对方设计良好的接口,在这里我们假设甲方提供的信息种类是固定的,你只需要审视自己负责的部分工作即可。首先,显而易见,主题的数量有可能发生变化:减少或增加。其次,甲方提供的信息是固定的,但是内容的表现形式也有可能变化。

三、代码实现

这里给出相关案例的C++代码实现:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

//@brief: 观察者(抽象接口)
class Observer
{
public:
    virtual void update(float temp, float humidity, float pressure) = 0;
};

//@brief: 主题(抽象接口)
class Subject
{
public:
    virtual void registerObserver(Observer* observer) = 0;
    virtual void removeObserver(Observer* observer)   = 0;
    virtual void notifyObservers()                    = 0;
};

//@brief: 表现形式(抽象接口)
class DisplayElement
{
public:
    virtual void display() = 0;
};

//@brief: 主题(具体实现)
class WeatherData : public Subject
{
private:
    vector<Observer*> observers {};

    float temperature {};
    float humidity {};
    float pressure {};

public:
    void registerObserver(Observer* observer) override
    {
        observers.push_back(observer);
    }

    void removeObserver(Observer* observer) override
    {
        auto it = find(observers.begin(), observers.end(), observer);
        if (it != observers.end())
        {
            observers.erase(it);
        }
    }

    void notifyObservers() override
    {
        for (auto observer : observers)
        {
            observer->update(temperature, humidity, pressure);
        }
    }

    void measurementsChanged()
    {
        notifyObservers();
    }

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

    float getTemperature() const
    {
        return temperature;
    }
    float getHumidity() const
    {
        return humidity;
    }
    float getPressure() const
    {
        return pressure;
    }
};

//@brief:观察者1号(具体实现)
class CurrentConditionsDisplay : public Observer, public DisplayElement
{
private:
    float temperature {};
    float humidity {};
    float pressure {};

    Subject* weatherData {};

public:
    CurrentConditionsDisplay(Subject* weatherData)
    {
        this->weatherData = weatherData;
        weatherData->registerObserver(this);
    }

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

    void display() override
    {
        cout << "手机通知 -- 天气预报" << endl;
        cout << "Current conditions: " << temperature << "°C, " << humidity << "%, " << pressure << " hPa" << endl;
    }
};

// 观察者2号(具体实现)
class StatisticsConditionDisplay : public Observer, public DisplayElement
{
private:
    float temp;
    float humid;
    float pressure;

    Subject* weather {};

public:
    StatisticsConditionDisplay(Subject* sub)
    {
        this->weather = sub;
        weather->registerObserver(this);
    }

    void update(float temp, float humidity, float pressure) override
    {
        this->temp     = temp;
        this->humid    = humidity;
        this->pressure = pressure;
        display();
    }
    void display()
    {
        cout << "电视节目 -- 天气预报" << endl;
        cout << "今日温度: " << temp << endl;
        cout << "今日湿度: " << humid << endl;
        cout << "今日气压: " << pressure << endl;
    }
};
//测试代码
int main()
{
    WeatherData*               weatherData = new WeatherData;

    CurrentConditionsDisplay   currentDisplay { weatherData };
    StatisticsConditionDisplay statisticsDisplay { weatherData };

    weatherData->setMeasurements(80, 65, 30.4f);
    cout << endl << endl;
    weatherData->setMeasurements(82, 70, 29.2f);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值