意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。
动机
将一个系统分割成一系列相互协作的类有一个常见的副作用:需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,因为这样降低了它们的可重用性。
适用性
- 当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
- 当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变。
- 当一个对象必须通知其他对象,而它又不能假定其他对象是谁。换言之。你不希望这些对象是紧密耦合的。
类图
例子场景
气象观察站追踪温度、湿度、气压数值,需要有一个布告板,分别显示目前的状况(温度、湿度、气压),每当有新的数据生成,布告板需要实时更新。
实现
Subject.h
#pragma once
class Observer;
class Subject
{
public:
Subject();
virtual void registerObserver(Observer* pObserver) = 0;
virtual void removeObserver(Observer* pObserver) = 0;
virtual void notifyObserver() = 0;
};
Subject.cpp
#include "Subject.h"
Subject::Subject()
{
}
Observer.h
#pragma once
class Observer
{
public:
Observer();
virtual void update(const float& temperature, const float& humidity, const float& pressure) = 0;
};
Observer.cpp
#include "Observer.h"
Observer::Observer()
{
}
WeatherData.h
#pragma once
#include "Subject.h"
#include <vector>
class Observer;
class WeatherData : public Subject
{
public:
WeatherData();
void registerObserver(Observer* pObserver) override;
void removeObserver(Observer* pObserver) override;
void notifyObserver() override;
void measurementsChanged();
void setMeasurements(const float& temperature, const float& humidity, const float& pressure);
private:
std::vector<Observer*> m_observers;
float m_temperature;
float m_humidity;
float m_pressure;
};
WeatherData.cpp
#include "WeatherData.h"
#include "Observer.h"
WeatherData::WeatherData()
: m_temperature(0)
, m_humidity(0)
, m_pressure(0)
{
}
void WeatherData::registerObserver(Observer* pObserver)
{
m_observers.push_back(pObserver);
}
void WeatherData::removeObserver(Observer* pObserver)
{
for (size_t i = 0; i < m_observers.size(); ++i)
{
if (pObserver == m_observers[i])
{
m_observers.erase(m_observers.begin() + i);
break;
}
}
}
void WeatherData::notifyObserver()
{
for (size_t i = 0; i < m_observers.size(); ++i)
{
m_observers[i]->update(m_temperature, m_humidity, m_pressure);
}
}
void WeatherData::measurementsChanged()
{
notifyObserver();
}
void WeatherData::setMeasurements(const float& temperature, const float& humidity, const float& pressure)
{
this->m_temperature = temperature;
this->m_humidity = humidity;
this->m_pressure = pressure;
measurementsChanged();
}
CurrentConditionsDisplay.h
#pragma once
#include "Observer.h"
class Subject;
class CurrentConditionsDisplay : public Observer
{
public:
CurrentConditionsDisplay(Subject* pWeatherData);
void update(const float& temperature, const float& humidity, const float& pressure) override;
private:
void display();
float m_temperature;
float m_humidity;
Subject* m_pWeatherData;
};
CurrentConditionsDisplay.cpp
#include "CurrentConditionsDisplay.h"
#include "Subject.h"
#include <iostream>
CurrentConditionsDisplay::CurrentConditionsDisplay(Subject* pWeatherData)
: m_temperature(0)
, m_humidity(0)
, m_pWeatherData(pWeatherData)
{
m_pWeatherData->registerObserver(this);
}
void CurrentConditionsDisplay::update(const float& temperature, const float& humidity, const float& pressure)
{
this->m_temperature = temperature;
this->m_humidity = humidity;
display();
}
void CurrentConditionsDisplay::display()
{
std::cout << "Current conditions: " << m_temperature << std::endl;
std::cout << "Humidity: " << m_humidity << std::endl;
}
main.cpp
#include "WeatherData.h"
#include "CurrentConditionsDisplay.h"
#include <memory>
int main()
{
std::shared_ptr<WeatherData> pWeatherData = std::make_shared<WeatherData>();
std::shared_ptr<CurrentConditionsDisplay> pCurrentConditionsDisplay = std::make_shared<CurrentConditionsDisplay>(pWeatherData.get());
pWeatherData->setMeasurements(2.3, 1.0, 4.5);
pWeatherData->setMeasurements(3.5, 7.0, 4.1);
return 0;
}