目录
三、建立布告板 CCurrentConditionsDisplay
摘要
观察者设计模式可以类比为:电子报纸出版社为主题(Subject),而订阅电子报纸的人为观察者(Observer),只要有新的事件,出版社就会给每一个订阅者发送信息。观察者可以注册订阅、取消订阅,而出版社可以通知所有的订阅者。
类关系图:
一、定义接口
1.1 定义主题接口: CSubject
#pragma once
#include "Observer.h"
//CSubject:出版者
//接口类
class CSubject
{
public:
CSubject(void);
~CSubject(void);
public:
virtual void RegisterObserver(CObserver* pObserver) = 0;
virtual void RemoveObserver(CObserver* pObserver) = 0;
virtual void NotifyObservers() = 0;
};
#include "stdafx.h"
#include "Subject.h"
#include "Observer.h"
CSubject::CSubject(void)
{
}
CSubject::~CSubject(void)
{
}
1.2 定义观察者接口 CObserver
#pragma once
//CObserver:订阅者
//接口
class CObserver
{
public:
CObserver(void);
virtual ~CObserver(void);
public:
virtual void Update(double dTemperature,double dTumidity,double dPressure) = 0; //只有一个Updete方法
};
#include "stdafx.h"
#include "Observer.h"
CObserver::CObserver(void)
{
}
CObserver::~CObserver(void)
{
}
1.3 定义显示接口 CDisplayElement
#pragma once
//接口
class CDisplayElement
{
public:
CDisplayElement(void);
virtual ~CDisplayElement(void);
public:
virtual void Display() = 0;
};
#include "stdafx.h"
#include "DisplayElement.h"
CDisplayElement::CDisplayElement(void)
{
}
CDisplayElement::~CDisplayElement(void)
{
}
二、在CWeatherData 中实现主题接口
#pragma once
#include "afx.h"
#include <vector>
#include "Observer.h"
#include "Subject.h"
//主题是正在拥有数据的人
//在CWeatherData实现CSubject的接口
class CWeatherData : public CSubject
{
public:
CWeatherData(void);
virtual ~CWeatherData(void);
void Init();
public:
virtual void RegisterObserver(CObserver* pObserver);
virtual void RemoveObserver(CObserver* pObserver);
virtual void NotifyObservers();
void MeasurementsChanged();
void SetMeasurements(const double dTemperature,const double dHumitity,const double dPressure);
double GetTemperature() const;
double GetHumidity() const;
double GetPressure() const;
private:
std::vector<CObserver*> m_pArrObserver; //无数个观察者(订阅者)
double m_dTemperature;
double m_dHumidity;
double m_dPressure;
};
#include "stdafx.h"
#include "WeatherData.h"
CWeatherData::CWeatherData(void)
{
Init();
}
CWeatherData::~CWeatherData(void)
{
for (auto it = m_pArrObserver.begin(); it != m_pArrObserver.end(); it++)
{
if ((*it) != nullptr)
{
delete *it;
(*it) = nullptr;
}
}
}
void CWeatherData::Init()
{
m_dTemperature = 0.0;
m_dHumidity = 0.0;
m_dPressure = 0.0;
}
//注册观察者
void CWeatherData::RegisterObserver(CObserver* pObserver)
{
m_pArrObserver.push_back(pObserver);
}
//删除观察者
void CWeatherData::RemoveObserver(CObserver* pObserver)
{
for (auto it = m_pArrObserver.begin(); it != m_pArrObserver.end(); it++)
{
if (*it == pObserver)
{
m_pArrObserver.erase(it);
}
}
}
//通知观察者
void CWeatherData::NotifyObservers()
{
for (auto it = m_pArrObserver.begin(); it != m_pArrObserver.end(); it++)
{
(*it)->Update(m_dTemperature, m_dHumidity, m_dPressure);
}
}
//信息发生变化
void CWeatherData::MeasurementsChanged()
{
NotifyObservers();
}
void CWeatherData::SetMeasurements(const double dTemperature,const double dHumitity,const double dPressure)
{
m_dTemperature = dTemperature;
m_dHumidity = dHumitity;
m_dPressure = dPressure;
MeasurementsChanged();
}
double CWeatherData::GetTemperature() const
{
return m_dTemperature;
}
double CWeatherData::GetHumidity() const
{
return m_dHumidity;
}
double CWeatherData::GetPressure() const
{
return m_dPressure;
}
三、建立布告板 CCurrentConditionsDisplay
#pragma once
#include "Observer.h"
#include "DisplayElement.h"
#include "Subject.h"
//根据CWeatherData对象显示当前观测值
class CCurrentConditionsDisplay : public CObserver, public CDisplayElement
{
public:
CCurrentConditionsDisplay(CSubject* pWeatherData);
virtual ~CCurrentConditionsDisplay(void);
public:
void Update(double dTemperature,double dTumidity,double dPressure);
void Display();
private:
CSubject* m_pWeatherData;
double m_dTemperature;
double m_dHumidity;
double m_dPressure;
};
#include "stdafx.h"
#include "CurrentConditionsDisplay.h"
#include "WeatherData.h"
CCurrentConditionsDisplay::CCurrentConditionsDisplay(CSubject* pWeatherData)
{
m_pWeatherData = new CWeatherData;
*m_pWeatherData = *pWeatherData;
ASSERT(m_pWeatherData);
if (m_pWeatherData != nullptr)
{
m_pWeatherData->RegisterObserver(this);
}
}
CCurrentConditionsDisplay::~CCurrentConditionsDisplay(void)
{
delete m_pWeatherData;
}
void CCurrentConditionsDisplay::Update(double dTemperature,double dTumidity,double dPressure)
{
m_dTemperature = dTemperature;
m_dHumidity = dTumidity;
m_dPressure = dPressure;
Display();
}
void CCurrentConditionsDisplay::Display()
{
CString str;
str.Format(_T("Current conditions: %.1f degrees , Humidity: %.1f, Pressure : %.1f"), m_dTemperature, m_dHumidity, m_dPressure);
AfxMessageBox(str,MB_OK);
}
四、启动气象站 CWeatherStation
#pragma once
class CWeatherStation
{
public:
CWeatherStation(void);
~CWeatherStation(void);
public:
void Main();
};
#include "stdafx.h"
#include "WeatherStation.h"
#include "WeatherData.h"
#include <memory>
#include "CurrentConditionsDisplay.h"
#include "StaticDisplay.h"
#include "ForcastDisplay.h"
#include "Observer.h"
CWeatherStation::CWeatherStation(void)
{
}
CWeatherStation::~CWeatherStation(void)
{
}
void CWeatherStation::Main()
{
CWeatherData* pWeatherData = new CWeatherData;
//当前天气状况布告板
CCurrentConditionsDisplay* pCurrentDisplay = new CCurrentConditionsDisplay(pWeatherData);
//天气统计布告板
CStatisticsDisplay* pStatisticsDisplay = new CStatisticsDisplay(pWeatherData);
pWeatherData->RegisterObserver(pStatisticsDisplay);
//天气预报布告板
CForcastDisplay* pForcastDisplay = new CForcastDisplay(pWeatherData);
pWeatherData->RegisterObserver(pForcastDisplay);
pWeatherData->SetMeasurements(80.0, 65.0, 30.4);
pWeatherData->SetMeasurements(82.0, 70.0, 29.2);
pWeatherData->SetMeasurements(78.0, 90.0, 29.2);
delete pWeatherData;
}
五、完整代码实现
https://github.com/mc-liyanliang/Design-patterns/tree/master/Observer%20Pattem
六、参考资料:
《Head First设计模式》