定义
观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,他的所有依赖者都会收到通知并自动更新。
要点
1)观察者模式定义了对象之间的一对多的关系。
2)主题(被观察者)用一个共同接口(Observer)来更新观察者。
3)观察者和被观察者之间用松耦合方式结合,被观察者不知道观察者的细节,只知道观察者实现了观察者接口。
4)使用此模式,可以从被观察者车推(push)或拉(pull)数据(然而,推的方式被认为更“正确”)。
5)有多个观察者是,不可以依赖特定的通知次序。
类图
Subject:主题接口,对象使用此接口注册为观察者,或者把自己从观察者中删除。
Oberver:所有的观察者必须实现观察者接口,这个接口只有update()一个方法,当主题状态改变时会被调用。
ConcreteSubject:主题,必须实现主题接口的三个方法,当主题状态变化是通过notifyObserver()方法更新所有观察者。
concreteOberver:具体观察者,可以是实现此接口的任意类。观察者必须注册具体主题,以便接收更新。
设计原则
为了交互对象之间的松耦合设计而努力。
松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的互相依赖降到了最低。
1)关于观察者,主题之知道观察者实现了某个接口(Observer接口)。主题不需要知道观察者的具体类是谁、做了写什么活着其他任何细节。
2)任何时候都可以增加新的观察者。
3)任何时候都可以删除或者取代某个或者某些观察者。
4)当有新的观察者出现时,主题代码不需要修改。只需要新的观察者实现此观察者接口(Observer接口),然后注册为观察者即可。
5)改变主题或观察者其中一方,并不影响另一方。因为两者是松耦合,只要他们之间的接口仍被遵守,我们就可以自由的改变他们。
示例
现在通过实现一个气象站示例。当气象站的状态发生变化是,需要通知不同的布告板来更新状态,如下为代码:
Subject.h
#ifndef SUBJECT_H
#define SUBJECT_H
#include "Observer.h"
/**
* 主题(被观察者)接口
*/
class Subject {
public:
virtual ~Subject(){}
virtual void registerObserver(Observer* o) = 0;
virtual void removeObserver(Observer* o) = 0;
virtual void notifyObserver() = 0;
};
#endif
WeatherData.h
#ifndef WEATHERDATA_H
#define WEATHERDATA_H
#include "Observer.h"
#include "Subject.h"
#include <list>
using namespace std;
/**
* 气象站(被观察者实例,一般只有一个)
*/
class WeatherData : public Subject {
private:
list<Observer*> m_observers;
float m_temperature;
float m_humidity;
float m_pressure;
public:
WeatherData(){}
void registerObserver(Observer* o)
{
m_observers.push_back(o);
}
void removeObserver(Observer* o)
{
// 从m_observers列表中删除o
list<Observer*>::iterator i;
for (i=m_observers.begin(); i!=m_observers.end(); i++) {
if (*i == o) {
m_observers.erase(i++);
}
}
}
void notifyObserver()
{
list<Observer*>::iterator i;
Observer* observer;
for (i=m_observers.begin(); i!=m_observers.end(); i++) {
// 调用每一个观察者的update方法
observer = *i;
observer->update();
}
}
float getTemperature()
{
return m_temperature;
}
float getHumidity()
{
return m_humidity;
}
float getPressure()
{
return m_pressure;
}
void measurementChanged()
{
notifyObserver();
}
void setMeasurements(float temp, float humidity, float pressure)
{
this->m_temperature = temp;
this->m_humidity = humidity;
this->m_pressure = pressure;
measurementChanged();
}
// WeatherData的其他方法
};
#endif
Oberver.h
#ifndef OBSERVER_H
#define OBSERVER_H
/**
* 观察者接口
*/
class Observer {
public:
virtual ~Observer(){}
virtual void update() = 0;
};
#endif
CurrentConditionsDisplay.h
#ifndef CURRENTCONDITIONSDISPLAY_H
#define CURRENTCONDITIONSDISPLAY_H
#include "WeatherData.h"
#include "Observer.h"
#include "Subject.h"
#include <iostream>
using std::cout;
/**
* 显示目前状况(观察者实例,有多个)
*/
class CurrentConditionsDisplay : public Observer {
private:
float m_temperature;
float m_humidity;
Subject* m_weatherData;
public:
CurrentConditionsDisplay(Subject* weatherData)
{
this->m_weatherData = weatherData;
weatherData->registerObserver(this);
}
void update()
{
WeatherData* weatherData = dynamic_cast<WeatherData*>(this->m_weatherData);
if (weatherData) {
this->m_temperature = weatherData->getTemperature();
this->m_humidity = weatherData->getHumidity();
display();
}
}
void display()
{
cout << "corrent conditions:";
cout << "temperature:" << m_temperature ;
cout << " humidity:" << m_humidity << "%" << endl;
}
};
#endif
TemperatureOnlyDisplay.h
#ifndef __TEMPERATUREONLYDISPLAY_H__
#define __TEMPERATUREONLYDISPLAY_H__
#include "WeatherData.h"
#include "Observer.h"
#include "Subject.h"
#include <iostream>
using std::cout;
using std::endl;
class TemperatureOnlyDisplay : public Observer
{
public:
TemperatureOnlyDisplay(Subject* wd)
{
m_weatherData = wd;
wd->registerObserver(this);
}
void update()
{
WeatherData* weatherData = dynamic_cast<WeatherData*>(this->m_weatherData);
temp = weatherData->getTemperature();
display();
}
void display()
{
cout << "TemperatureOnlyDisplay displaying, ";
cout << "Temperuture: " << temp << endl;
cout << endl;
}
private:
Subject *m_weatherData;
int temp;
int humidity;
int pressure;
};
#endif
main.cpp
#include <iostream>
#include "WeatherData.h"
#include "CurrentConditionsDisplay.h"
#include "TemperatureOnlyDisplay.h"
using namespace std;
int main()
{
WeatherData* weatherData = new WeatherData();
CurrentConditionsDisplay* currentDisplay = new CurrentConditionsDisplay(weatherData);
TemperatureOnlyDisplay* temperatureDisplay = new TemperatureOnlyDisplay(weatherData);
weatherData->setMeasurements(80, 65, 30.4);
weatherData->removeObserver(currentDisplay);
weatherData->setMeasurements(88, 55, 36.4);
delete temperatureDisplay;
delete currentDisplay;
delete weatherData;
return 0;
}
Makefile
CXX = g++
CFLAGS = -Wall
LDFLAGS =
target = res
srcs = main.cpp
objs = $(srcs:.cpp=.o)
.PHONY: all
all: $(target)
$(target): $(objs)
$(CXX) $(LDFLAGS) -o $(target) $^
$(objs):%.o:%.cpp
$(CXX) $(CFLAGS) -c -o $@ $<
clean:
rm -f $(target) *.o
测试
测试结果如下所示:
本文完整代码下载地址:https://github.com/zhaoxd298/ObserverPattern