• c++设计模式:观察者模式(Observer Pattern)


    定义:

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

    场景:

    我们有一个气象站,我们通过WeatherData获取气象站的最新数据,并更新布告板上的数据。我们定义了两个布告板,一个是温度计,显示最新的温度,另一个布告板就是显示当前的所有温度、湿度和气压的最新数据。

    类图:

    c++代码如下:

    #include <iostream>
    #include <list>
    #include <string>
    #include <algorithm>
    using namespace std;

    class Observer;

    // 主题
    class Subject
    {
    public:
    virtual void registerObserver(Observer* o) = 0;
    virtual void removeObserver(Observer* o) = 0;
    virtual void notifyObserver() = 0;
    float getTemperature();
    float getHumidity();
    float getPressure();
    protected:
    float m_temperature;
    float m_humidity;
    float m_pressure;
    };

    // 观察者
    class Observer
    {
    public:
    Observer(Subject* pWeaterData);
    virtual ~Observer() {};
    virtual void update() = 0;
    Subject* getWeaterData();
    protected:
    Subject* m_weaterData;
    };

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

    class WeatherData:public Subject
    {
    public:
    WeatherData();
    ~WeatherData();
    void registerObserver(Observer* o);
    void removeObserver(Observer* o);
    void notifyObserver();
    void measurementsChanged();
    void setMeasurements(float temperature, float humidity, float pressure);
    private:
    list<Observer*> m_lObserver;
    };

    // 当前条件显示
    class CurrentConditionsDisplay:public Observer,public DisplayElement
    {
    public:
    CurrentConditionsDisplay(Subject* pWeaterData);
    ~CurrentConditionsDisplay();
    void update();
    void display();
    private:
    float m_template; // 温度
    float m_humidity; // 湿度
    float m_pressure; // 气压
    };

    // 温度计
    class Thermometer:public Observer,public DisplayElement
    {
    public:
    Thermometer(Subject* pWeaterData);
    ~Thermometer();
    void update();
    void display();
    private:
    float m_template; // 温度
    };

    float Subject::getTemperature()
    {
    return m_temperature;
    }

    float Subject::getHumidity()
    {
    return m_humidity;
    }

    float Subject::getPressure()
    {
    return m_pressure;
    }

    Observer::Observer(Subject* pWeaterData)
    {
    m_weaterData = pWeaterData;
    }

    Subject* Observer::getWeaterData()
    {
    return m_weaterData;
    }

    WeatherData::WeatherData()
    {
    m_temperature = 0;
    m_humidity = 0;
    m_pressure = 0;
    }

    WeatherData::~WeatherData()
    {
    list<Observer*>::iterator iter, temp;
    for (iter=m_lObserver.begin(); iter!=m_lObserver.end(); ++iter)
    {
    delete (*iter);
    }
    m_lObserver.clear();
    }

    void WeatherData::registerObserver(Observer* o)
    {
    m_lObserver.push_back(o);
    }

    void WeatherData::removeObserver(Observer* o)
    {
    list<Observer*>::iterator iter;

    iter = std::find(m_lObserver.begin(), m_lObserver.end(), o);

    if (m_lObserver.end() != iter)
    {
    m_lObserver.erase(iter);
    }
    }

    void WeatherData::notifyObserver()
    {
    list<Observer*>::iterator iter;
    for (iter=m_lObserver.begin(); iter!=m_lObserver.end(); ++iter)
    {
    (*iter)->update();
    }
    }

    void WeatherData::measurementsChanged()
    {
    notifyObserver();
    }

    void WeatherData::setMeasurements(float temperature, float humidity, float pressure)
    {
    m_temperature = temperature;
    m_humidity = humidity;
    m_pressure = pressure;
    measurementsChanged();
    }

    CurrentConditionsDisplay::CurrentConditionsDisplay(Subject* pWeaterData):Observer(pWeaterData)
    {
    pWeaterData->registerObserver(this);
    }
    CurrentConditionsDisplay::~CurrentConditionsDisplay()
    {
    m_weaterData = NULL;
    }
    void CurrentConditionsDisplay::update()
    {
    m_template = m_weaterData->getTemperature();
    m_humidity = m_weaterData->getHumidity();
    m_pressure = m_weaterData->getPressure();
    display();
    }
    void CurrentConditionsDisplay::display()
    {
    printf("Current conditions %f0.2F degrees and %0.2f%s humidity and pressure %0.2f\n",m_template,m_humidity,"%",m_pressure);
    }

    Thermometer::Thermometer(Subject* pWeaterData):Observer(pWeaterData)
    {
    pWeaterData->registerObserver(this);
    }

    Thermometer::~Thermometer()
    {
    m_weaterData = NULL;
    }

    void Thermometer::update()
    {
    m_template = m_weaterData->getTemperature();
    display();
    }

    void Thermometer::display()
    {
    printf("Current conditions %f0.2F degrees\n",m_template);
    }

    int main()
    {
    WeatherData* pWeatherData = new WeatherData();
    CurrentConditionsDisplay* pCurrentConditionsDisplay = new CurrentConditionsDisplay(pWeatherData);
    Thermometer* pThermometer = new Thermometer(pWeatherData);
    pWeatherData->setMeasurements(123,456,789);

    // 当移除观察者后,需要手动释放内存
    pCurrentConditionsDisplay->getWeaterData()->removeObserver(pCurrentConditionsDisplay);
    pWeatherData->setMeasurements(789,456,123);

    // 当再次注册后,内存交由主题管理
    pCurrentConditionsDisplay->getWeaterData()->registerObserver(pCurrentConditionsDisplay);
    pWeatherData->setMeasurements(135,257,479);

    delete pWeatherData;
    return 0;
    }

    运行后结果如下:

    Current conditions 123.000F degrees and 456.00% humidity and pressure 789.00
    Current conditions 123.00F degrees
    Current conditions 789.00F degrees
    Current conditions 135.00F degrees
    Current conditions 135.00F degrees and 257.00% humidity and pressure 479.00


    参考资料:《Head First 设计模式》

  • 相关阅读:
    【TPCH】工具安装与生成数据
    【sysbench】point_select测试方法与脚本
    【sysbench】read_write测试方法与脚本
    【Ubuntu】mysql 5.7 server与client安装
    DataX进行数据同步总结
    关于 h5 获取摄像头图像
    如何在 express 中创建 websocket 接口以及一些相关问题的处理
    js中运算符的优先级
    echarts 修改legend字体颜色、x轴或y轴文本字体颜色改变
    echarts gauge仪表盘配置
  • 原文地址:https://www.cnblogs.com/osyun/p/2254376.html
Copyright © 2020-2023  润新知