观察者模式:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新.
松耦合:两个对象松耦合时,它们依然可以交互,但并不太清楚彼此的细节,相互依赖很低,这样可以建立有弹性的OO系统,应对变化.
要点:
1.观察者模式定义了对象之间一对多的关系
2.主题用一个共同的接口来更新观察者
3.观察者和可观察者之间用松耦合结合,可观察者不知道观察者的细节,只知道观察者实现了
观察者接口
4.使用此模式时,你可从被观察者处推或拉数据(推的方式被认为更“正确”)
5.有多个观察者时,不可以依赖特定的通知次序
设计原则:为交互对象之间的松耦合设计而努力
[img]http://dl.iteye.com/upload/attachment/501684/55cf0c19-48c5-3b1b-8f47-920b91f277b7.png[/img]
主题接口:Subject.h
#ifndef SUBJECT_H
#define SUBJECT_H
#include"Observer.h"
class Subject{
public:
virtual void registerObserver(Observer* obs)=0;//增加
virtual void removeObserver(Observer* obs)=0;//删除
virtual void notifyObserver()=0;//通知观察者准备更新
};
#endif // SUBJECT_H
观察者接口:Observer.h
#ifndef OBSERVER_H
#define OBSERVER_H
class Observer{
public:
virtual void update(float t,float p=0,float=0)=0;//更新全部数据
virtual void update()=0;//只更新自己需要的数据
virtual void display()=0;
};
#endif // OBSERVER_H
主题实例:
weatherData.h
#ifndef WEATHERDATA_H
#define WEATHERDATA_H
#include"Subject.h"
#include<list>
using namespace std;
class WeatherData:public Subject{
private:
list<Observer*> mObsList;
float mTemperature;
float mHumidity;
float mPressure;
bool mChange;//增加一个变量,以备不时之需,比如当数据发生微小变化时不改更新
public:
explicit WeatherData(float t=0,float h=0,float p=0);
void registerObserver(Observer* obs);
void removeObserver(Observer* obs);
void notifyObserver();
void setMeasurement(float t,float h,float p);
void measurementChanged();
float getTemperature()const;
float getHumidity()const;
float getPressure()const;
bool getChanged()const;
void setChanged(bool c);
};
#endif // WEATHERDATA_H
weatherData.cpp
#include"WeatherData.h"
WeatherData::WeatherData(float t, float h, float p)
:mTemperature(t),mHumidity(h),mPressure(p){
}
void WeatherData::registerObserver(Observer *obs){
mObsList.push_back(obs);
}
void WeatherData::removeObserver(Observer *obs){
mObsList.remove(obs);
}
void WeatherData::notifyObserver(){
list<Observer*>::iterator iter = mObsList.begin();
while(iter!=mObsList.end()){
//(*iter)->update();//拉数据
(*iter)->update(mTemperature,mHumidity,mPressure);//推送数据
++iter;
}
}
/*
TODO:这里可以利用change来灵活的更新信息
*/
void WeatherData::setMeasurement(float t, float h, float p){
mTemperature = t;
mHumidity = h;
mPressure = p;
measurementChanged();
}
void WeatherData::measurementChanged(){
notifyObserver();
}
void WeatherData::setChanged(bool c){
mChange = c;
}
bool WeatherData::getChanged()const{
return mChange;
}
/*
支持主动接收数据
*/
float WeatherData::getTemperature()const{
return mTemperature;
}
float WeatherData::getHumidity()const{
return mHumidity;
}
float WeatherData::getPressure()const{
return mPressure;
}
观察者实例:
CurrentTemperature.h
#ifndef CURRENTCONDITION_H
#define CURRENTCONDITION_H
#include"Observer.h"
#include"Subject.h"
class CurrentTemperature:public Observer{
private:
float mTemperature;
float mHumidity;
float mPressure;
Subject* mSub;
public:
explicit CurrentTemperature(Subject* sub);
void update(float t,float h=0,float p=0);
void update();
void display();
};
#endif
CurrentTemperature.cpp
#include"Observer.h"
#include"CurrentTemperature.h"
#include"WeatherData.h"
#include<iostream>
using namespace std;
CurrentTemperature::CurrentTemperature(Subject* sub){
mSub = sub;//将Subject保存起来,为"拉"数据做准备
sub->registerObserver(this);
}
/*
我其实只要温度这一个数据,你干嘛把所有的信息都推送给我?
我直接根据自身需求去取数据多好.
有时候这很烦人,就好像3G用户喜欢把手机推送给关掉。
*/
void CurrentTemperature::update(){
if(WeatherData *wd = dynamic_cast<WeatherData*>(mSub)){
update(wd->getTemperature());
}
}
/*
但是你在构造的时候保存了我的指针,这意味着你们可以进来大肆挖掘
我的数据,我不得不提供公开的getter(),但每次想得到的时候都来找我,
你需要从我这多次getXXX(),这样多麻烦,而且像Statistic和Forecast
他们可不想每次到我这拉数据,我直接把所有的数据都给你们都更新
了,这样大部分观察者还是满意的多好!
-----------推送数据被认为更“正确"----------------
这样松耦合,观察者不需要持有主题对象的指针,
就好像是“你不要找我拿信息,我会一有新信息就帮大家都更新!”
*/
void CurrentTemperature::update(float t, float h, float p){
mTemperature = t;
mHumidity = h;
mPressure = p;
}
void CurrentTemperature::display(){
cout << "current temperature is " << mTemperature;
}
int main(){
WeatherData* wd = new WeatherData;
Observer* obs = new CurrentTemperature(wd);
wd->setMeasurement(30,20,10);
obs->display();
}
current temperature is 30