案例:开发一个天气检测的APP,当天气信息发生变化时,把信息实时更新到布告板上。利用WeatherData对象获取数据并更新到各个布告板上。
出版者 + 订阅者 = 观察者模式;
当出版者出版新的报纸时自动给订阅了报纸的订阅者发送信息。
出版者改称为“主题”(Subject)
订阅者改称为“观察者”(Observer)
后续新增的观察者可以通过注册成为主题对象的观察者,也可以通过操作使自己不再是该主题对象的观察者。
观察者模式:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
设计原则:为了交互对象之间的松耦合设计而努力。
主题对象和观察者之间就采用松耦合方式结合。主题对象不知道观察者的细节,只知道观察者实现了主题对象接口。
类图:
注:另外一种实现为把getTemperature() 和 getHumidity() 放在WeatherData类中,update()函数的参数为(int temperature, int humidity);
本实现是把整个Subject对象作为参数传入给update()函数,方便后续的扩展,不限制update()函数参数成员类型;
指针:聚合关系
成员:组合关系
setMeasurements() -> measurementChanged() -> notifyObserver() -> update() -> display();
实现如下:
subject.h:
#ifndef SUBJECT_H
#define SUBJECT_H
#include "observer.h"
class Subject {
public:
virtual void registerObserver(Observer* o) = 0;
virtual void removeObserver(Observer* o) = 0;
virtual void notifyObserver() = 0;
virtual int getTemperature() = 0;
virtual int getHumidity() = 0;
};
#endif // SUBJECT_H
weatherData.h:
#ifndef WEATHERDATA_H
#define WEATHERDATA_H
#include <vector>
#include "subject.h"
class WeatherData : public Subject {
public:
virtual void registerObserver(Observer* o) override;
virtual void removeObserver(Observer* o) override;
virtual void notifyObserver() override;
virtual int getTemperature() override;
virtual int getHumidity() override;
void setMeasurements(int temperature, int humidity);
void measurementsChanged();
private:
vector<Observer*> m_observersV; // 0规则
int m_temperature;
int m_humidity;
};
// 注册
void WeatherData::registerObserver(Observer* o)
{
m_observersV.push_back(o);
}
// 删除
void WeatherData::removeObserver(Observer* o)
{
vector<Observer*>::iterator itr = m_observersV.begin();
while (itr != m_observersV.end()) {
if(*itr == o)
{
itr = m_observersV.erase(itr);
}
else
{
itr ++;
}
}
}
// 通知观察者
void WeatherData::notifyObserver()
{
for(int i = 0; i < m_observersV.size(); i++)
{
Observer* obs = (Observer*)m_observersV[i];
obs->update((Subject*) this);
}
}
void WeatherData::measurementsChanged()
{
notifyObserver();
}
void WeatherData::setMeasurements(int temperature, int humidity)
{
m_temperature = temperature;
m_humidity = humidity;
measurementsChanged();
}
int WeatherData::getHumidity()
{
return this->m_humidity;
}
int WeatherData::getTemperature()
{
return this->m_temperature;
}
#endif // WEATHERDATA_H
observer.h:
#ifndef OBSERVER_H
#define OBSERVER_H
#include <iostream>
using namespace std;
class Subject;
class Observer {
public:
virtual void update(Subject* subject) = 0;
};
#endif // OBSERVER_H
display.h:
#ifndef DISPLAY_H
#define DISPLAY_H
#include <iostream>
using namespace std;
class Display {
public:
virtual void display() = 0;
};
#endif // DISPLAY_H
temDisplay.h:
#ifndef TEMDISPLAY_H
#define TEMDISPLAY_H
#include "subject.h"
#include "display.h"
class TemDisplay : public Observer, public Display{
public:
TemDisplay(Subject* weatherData);
virtual void update(Subject* subject) override; // 传递一个指针不用指定特定的元素
virtual void display() override;
private:
Subject* m_weatherData; // 构造需要weather对象,方便后续的取消注册
int m_temperature;
};
TemDisplay::TemDisplay(Subject* weatherData)
{
m_weatherData = weatherData;
}
void TemDisplay::display()
{
cout << "当前温度为 " << m_weatherData->getTemperature() << " 度" << endl;
}
void TemDisplay::update(Subject* subject)
{
m_weatherData = subject;
cout << "温度显示器更新: ";
display();
}
#endif // TEMDISPLAY_H
humDisplay.h:
#ifndef HUMDISPLAY_H
#define HUMDISPLAY_H
#include "subject.h"
#include "display.h"
class HumDisplay : public Observer, public Display{
public:
HumDisplay(Subject* weatherData);
virtual void update(Subject* subject) override; // 传递一个指针不用指定特定的元素
virtual void display() override;
private:
Subject* m_weatherData; // 构造需要weather对象,方便后续的取消注册
int m_humidity;
};
HumDisplay::HumDisplay(Subject* weatherData)
{
m_weatherData = weatherData;
}
void HumDisplay::display()
{
cout << "当前湿度为 " << m_weatherData->getHumidity() << " %" << endl;
}
void HumDisplay::update(Subject* subject)
{
m_weatherData = subject;
cout << "湿度显示器更新: ";
display();
}
#endif // HUMDISPLAY_H
main.h:
/*
* 观察者模式
*
* date:2023-9-7
*/
#include "weatherData.h"
#include "temDisplay.h"
#include "humDisplay.h"
int main()
{
WeatherData* weatherData = new WeatherData();
Observer* temDisplay = new TemDisplay(weatherData);
Observer* humDisplay = new HumDisplay(weatherData);
weatherData->registerObserver(temDisplay);
weatherData->registerObserver(humDisplay);
weatherData->setMeasurements(20, 40);
puts("");
cout << "取消注册湿度显示器观察者\n" <<endl;
weatherData->removeObserver(humDisplay);
weatherData->setMeasurements(30, 30);
}
运行结果: