观察者模式:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新.

松耦合:两个对象松耦合时,它们依然可以交互,但并不太清楚彼此的细节,相互依赖很低,这样可以建立有弹性的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