观察者模式 Observer – 学习HeadFirst设计模式记录


1、HeadFirst上的标准实现,属于教学版。

2、参考Java内置实现,感觉更实用些。


 

1、HeadFirst上的标准实现,属于教学版。

接口声明:  

/*  说明:

 报纸出版社 + 订阅者 = 观察者模式 

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

 设计原则:
 为了交互对象之间的松耦合设计而努力。
*/

/* *
*  观察者,即订阅者
*/
class Observer
{
public:
     virtual  void Update( float temperature,  float humidity,  float pressure) =  0;
};

/* *
*  主题,相当于出版社
*/
class Subject
{
public:
     virtual  void RegisterObserver(Observer *observer) =  0;
     virtual  void RemoveObserver(Observer *observer) =  0;
     virtual  void NotifyObserver() =  0;
};

 

类实现:

#include <iostream>
#include <list>

#include  " main.h "


class WeatherData :  public Subject
{
public:

    WeatherData( float temperature= 0float humidity= 0float pressure= 0) : _temperature(temperature)
                                                                         , _humidity(humidity)
                                                                         , _pressure(pressure)
    {}
    /* 管理观察者 */
     virtual  void RegisterObserver(Observer *observer)
    {
        _observerList.push_back(observer);
    }
     virtual  void RemoveObserver(Observer *observer)
    {
        _observerList.remove(observer);
    }
     /*  通知观察者,推送新数据  */
     virtual  void NotifyObserver()
    {
        std::list<Observer*>::iterator it = _observerList.begin();
         for (; it != _observerList.end(); ++it)
        {
            (*it)->Update(_temperature, _humidity, _pressure);
        }
    }

     void SetData( float temperature,  float humidity,  float pressure)
    {
        _temperature = temperature;
        _humidity    = humidity;
        _pressure    = pressure;
        MeasurementsChanged();
    }
     void MeasurementsChanged()
    {
        NotifyObserver();
    }

     /*  查询接口  */
     float GetTemperature()  {  return _temperature; }  
     float GetHumidity()  {  return _humidity; }
     float GetPressure()  {  return _pressure; }

private:
    std::list<Observer*> _observerList;
     float _temperature;
     float _humidity;
     float _pressure;
};

class CurrentConditionDisplay :  public Observer
{
public:
    CurrentConditionDisplay(Subject *weatherData) : _weatherData(weatherData)
    {
        _weatherData->RegisterObserver( this);
    }
     /* 观察者接口*/
     virtual  void Update( float temperature,  float humidity,  float pressure)
    {
        Display(temperature, humidity, pressure);
    }
     virtual  void Display( float temperature,  float humidity,  float pressure)
    {
        std::cout <<  " Current Condition :  " << temperature <<  "  degrees,  " << humidity <<  " % humidity,  " << pressure <<  "  pa . " << std::endl;
    }

private:
    Subject *_weatherData;
};
//   class StatisticsDisplay : public Observer, public DisplayElement {};
//   class ForecastDisplay   : public Observer, public DisplayElement {};

int main()
{
    WeatherData weatheData;
    CurrentConditionDisplay currDisplay(&weatheData);
    weatheData.SetData( 23101);

     return  0;
}

 

2、参考Java内置实现,感觉更实用些。

1)将公共部分放入基类中(在Observable中管理观察者)。

2)告知观察者数据已更新,然后由观察者主动获取自己需要的数据。

 

接口声明:

#include <list>

class Observable;

/* *
*  观察者
*/
class Observer
{
public:
     /*  被观察者作为参数,因为一个观察者可以观察多个对象  */
     virtual  void Update(Observable *pObs /* , Object obj */) =  0;
};

/* *
*  被观察者,已实现观察者管理功能
*/
class Observable
{
public:
    Observable() {}
     virtual ~Observable() {}

     void RegisterObserver(Observer *observer)
    {
        _observerList.push_back(observer);
    }
     void RemoveObserver(Observer *observer)
    {
        _observerList.remove(observer);
    }
     /*  通知观察者  */
     void NotifyObserver()
    {
        std::list<Observer*>::iterator it = _observerList.begin();
         for (; it != _observerList.end(); ++it)
        {
            (*it)->Update( this);
        }
    }

private:
    std::list<Observer*> _observerList;
};

 

类实现:

#include <iostream>
#include <list>

#include  " main.h "


class WeatherData :  public Observable
{
public:
    
    WeatherData( float temperature= 0float humidity= 0float pressure= 0) : _temperature(temperature)
                                                                         , _humidity(humidity)
                                                                         , _pressure(pressure)
    {}
    
     void SetData( float temperature,  float humidity,  float pressure)
    {
        _temperature = temperature;
        _humidity    = humidity;
        _pressure    = pressure;
        MeasurementsChanged();
    }
     void MeasurementsChanged()
    {
        NotifyObserver();
    }
    
     /*  提供查询接口  */
     float GetTemperature()  {  return _temperature; }  
     float GetHumidity()  {  return _humidity; }
     float GetPressure()  {  return _pressure; }
    
private:
     float _temperature;
     float _humidity;
     float _pressure;
};


class CurrentConditionDisplay :  public Observer
{
public:
    CurrentConditionDisplay(Observable *weatherData) : _weatherData(weatherData)
    {
        _weatherData->RegisterObserver( this);
    }
     /*  观察者接口 */
     virtual  void Update(Observable *pObs /* , Object obj */)
    {
        WeatherData *pWeatheData =  dynamic_cast<WeatherData *>(pObs);
         if (NULL != pWeatheData)
        { /* 收到通知后,主动获取数据,然后显示 */
            Display(pWeatheData->GetTemperature(), pWeatheData->GetHumidity(), pWeatheData->GetPressure());
        }
    }
     virtual  void Display( float temperature,  float humidity,  float pressure)
    {
        std::cout <<  " Current Condition :  " << temperature <<  "  degrees,  " << humidity <<  " % humidity,  " << pressure <<  "  pa . " << std::endl;
    }
    
private:
    Observable *_weatherData;
};
//   class StatisticsDisplay : public Observer, public DisplayElement {};
//   class ForecastDisplay   : public Observer, public DisplayElement {};

int main()
{
    WeatherData weatheData;
    CurrentConditionDisplay currDisplay(&weatheData);
    weatheData.SetData( 23101);
    
     return  0;
}
  

 

VC6中,当使用dynamic_cast时,会有告警warnning,并且运行时会报错:

warning C4541: 'dynamic_cast' used on polymorphic type 'class xxxx with /GR-; unpredictable behavior may result

解决方法:

工程->设置->C/C++->分类->C++语言

选中允许RTTI

对于typeid的使用编译时没有警告,但是运行时也有问题,同样需要选中RTTI

 

你可能感兴趣的:(observer)