文章中部分内容和思路来自《Head First设计模式》
模式定义
定义了对象之间一对多的依赖,这样一来,当一个对象状态改变时,它的所有依赖者都会收到通知并自动更新。
模式类图
典型案例
1.案例需求
气象局需要我们构建一套系统,该系统有两个公告牌,分别用于显示当前天气状况(湿度、温度、气压)和未来几天的天气预报。当气象局发布新的天气数据时,公告牌能根据发布的天气数据即时更新。需保证程序有良好的扩展性,以便后续加入其他用途的公告牌。
2.情况分析
系统应该分为三个部分,其中气象站时刻采集实时天气信息,并将天气数据传送给WeatherData对象,WeatherData根据传送的数据不同状态不断变化,公告牌根据WeatherData的数据变化更新显示
3.实现类图
4.代码实现
------------
IObserver.h:
------------
#ifndef IOBSERVER_H
#define IOBSERVER_H
class IObserver
{
public:
virtual void update() = 0;
};
#endif // IOBSERVER_H
-----------
ISubject.h:
-----------
#ifndef ISUBJECT_H
#define ISUBJECT_H
class IObserver;
class ISubject
{
public:
virtual void registObserver(IObserver *ob) = 0;
virtual void removeObserver(IObserver *ob) = 0;
virtual void notifyObserver() = 0;
};
#endif // ISUBJECT_H
-----------
IDisplay.h:
-----------
#ifndef IDISPLAY_H
#define IDISPLAY_H
class IDisplay
{
public:
virtual void display() = 0;
};
#endif // IDISPLAY_H
-----------------
ForcaseDisplay.h:
-----------------
#ifndef FORCASEDISPLAY_H
#define FORCASEDISPLAY_H
#include <QList>
#include "IObserver.h"
#include "IDisplay.h"
#include "WeatherData.h"
class ForcaseDisplay : public IObserver, public IDisplay
{
public:
ForcaseDisplay(WeatherData *data);
public:
virtual void update();
virtual void display();
private:
QList<float> _temperoraInNextDays; // 未来几天温度
WeatherData *_data; // 天气信息
};
#endif // FORCASEDISPLAY_H
-------------------
ForcaseDisplay.cpp:
-------------------
#include "ForcaseDisplay.h"
#include <QDebug>
ForcaseDisplay::ForcaseDisplay(WeatherData *data)
{
_data = data;
_data->registObserver(this);
}
void ForcaseDisplay::update()
{
_temperoraInNextDays = _data->getTemperoraInNextDays();
display();
}
void ForcaseDisplay::display()
{
qDebug() << "未来几天温度 : " << _temperoraInNextDays;
}
------------------------------
CurrentConditionDisplay.h:
------------------------------
#ifndef CURRENTCONDITIONDISPLAY_H
#define CURRENTCONDITIONDISPLAY_H
#include "IObserver.h"
#include "IDisplay.h"
#include "WeatherData.h"
class CurrentConditionDisplay : public IObserver, public IDisplay
{
public:
CurrentConditionDisplay(WeatherData *data);
public:
virtual void update();
virtual void display();
private:
float _temperora; // 当前温度
float _humidity; // 当前湿度
float _pressure; // 当前气压
WeatherData *_data; // 天气信息
};
#endif // CURRENTCONDITIONDISPLAY_H
----------------------------
CurrentConditionDisplay.cpp:
----------------------------
#include "CurrentConditionDisplay.h"
#include <QDebug>
CurrentConditionDisplay::CurrentConditionDisplay(WeatherData *data)
{
_data = data;
_data->registObserver(this); // 订阅
}
void CurrentConditionDisplay::update()
{
_temperora = _data->getTemperora();
_humidity = _data->getHumidity();
_pressure = _data->getPressure();
display();
}
void CurrentConditionDisplay::display()
{
qDebug() << "今日温度 : " << _temperora
<< "今日湿度 : " << _humidity
<< "今日气压 : " << _pressure;
}
--------------
WeatherData.h:
--------------
#ifndef WEATHERDATA_H
#define WEATHERDATA_H
#include <QList>
#include "ISubject.h"
#include "IObserver.h"
class WeatherData : public ISubject
{
public:
WeatherData();
public:
virtual void registObserver(IObserver *ob);
virtual void removeObserver(IObserver *ob);
virtual void notifyObserver();
void setWeatherData(float temperora, float pressure, float humidity, QList<float> temperoraList);
float getTemperora() const;
float getPressure() const;
float getHumidity() const;
QList<float> getTemperoraInNextDays() const;
private:
QList<IObserver *> _observerList; // 观察者列表
QList<float> _temperoraInNextDays; // 未来几天温度
float _temperora; // 当前温度
float _humidity; // 当前湿度
float _pressure; // 当前气压
};
#endif // WEATHERDATA_H
----------------
WeatherData.cpp:
----------------
#include "WeatherData.h"
WeatherData::WeatherData()
{
}
void WeatherData::registObserver(IObserver *ob)
{
_observerList.append(ob);
}
void WeatherData::removeObserver(IObserver *ob)
{
_observerList.removeOne(ob);
}
void WeatherData::notifyObserver()
{
for (int i = 0; i < _observerList.length(); i++)
{
_observerList[i]->update();
}
}
void WeatherData::setWeatherData(float temperora, float pressure, float humidity, QList<float> temperoraList)
{
_temperora = temperora;
_pressure = pressure;
_humidity = humidity;
_temperoraInNextDays = temperoraList;
notifyObserver(); // 发布
}
float WeatherData::getTemperora() const
{
return _temperora;
}
float WeatherData::getPressure() const
{
return _pressure;
}
float WeatherData::getHumidity() const
{
return _humidity;
}
QList<float> WeatherData::getTemperoraInNextDays() const
{
return _temperoraInNextDays;
}
---------
main.cpp:
---------
/**
* 设计模式-观察者模式案例
* 要素:1,抽象观察者 2,抽象主题 3,具体观察者 4,具体主题
*/
#include <QCoreApplication>
#include "WeatherData.h"
#include "CurrentConditionDisplay.h"
#include "ForcaseDisplay.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
WeatherData data;
CurrentConditionDisplay cDis(&data);
ForcaseDisplay fDis(&data);
#if 1 // 去除构建警告,要不要都可以
Q_UNUSED(cDis)
Q_UNUSED(fDis)
#endif
QList<float> tempList;
tempList << 22.3 << 25.1 << 5.34 << 7.4;
data.setWeatherData(33.3, 23.3, 13.3, tempList); // 气象局只负责设置天气数据,布告牌自动更新
return a.exec();
}