• 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 设计模式》

  • 相关阅读:
    Artificial Intelligence: A Modern Approach Notes
    Android Studio: Error running 'app': no target device found. Mac
    证明 当 a=qb+r, gcd(a,b)=gcd(b,r),a,b,q,r 属于整数
    dmg 文件打不开,双击没反应
    vim tab size,8 空格改4空格
    zsh: command not found: sage
    PyCharm ImportError: No module named 'numpy' 但用 pip3 install numpy 又显示 已经下载
    GitHub Desktop Merge
    Android Studio Unable to access Android SDK addon list Mac
    conda 切换 python 环境 vscode
  • 原文地址:https://www.cnblogs.com/osyun/p/2254376.html
Copyright © 2020-2023  润新知