观察者模式(Observer Pattern)行为模式.
它是应用最多,影响最广的模式之一,因为Observer的一个实例Model/View/Control(MVC)结构在系统开发构架中有着很重要的地位和意义,MVC实现了业务逻辑和表示层的解耦。Observer模式是软件开发过程中必须要掌握的和使用的模式之一。Observer模式要解决的问题为:建立一个一(Subject)对多(Observer)的依赖关系,并且做到当“一”变化的时候,依赖这个“一”的多也能够同步改变。最常见的一个例子就是:对同一组数据进行统计分析时候,我们希望能够提供多种形式的表示(例如以表格进行统计显示、柱状图统计显示、百分比统计显示等)。这些表示都依赖于同一组数据,我们当然需要当数据改变的时候,所有的统计的显示都能够同时改变。Observer模式就是解决了这一个问题。
设计原则:为了交互对象之间的松耦合设计而努力。
出版者+订阅者=观察者模式
定义:定义了对象之间的一对多的依赖,这样一来,当一个对象改变状态,它的所有依赖者都会收到通知并自动更新。
主题对象(管理某些数据)------(一旦主题内的数据改变就会通知观察者)--------à观察者对象(狗对象,猫对象)
实现观察者模式的方法不止一种,但是以包含Subject和Observer接口的类设计的做法最常见。
气象站观察者模式类设计图:
注意这里的Observer的Update操作并不在Observer改变了Subject目标状态的时候就对自己进行更新,这个更新操作要延迟到Subject对象发出Notify通知所有Observer进行修改(调用Update)。
C++实现:
Subject.h头文件
#ifndef _SUBJECT_H_
#define _SUBJECT_H_
#include
#include
using namespace std;
class Observer;
class Subject //主题接口
{
public:
virtual ~Subject();
virtual void Register(Observer* obv);
virtual void Remove(Observer* obv);
virtual void Notify();//当主题改变时,用这个方法通知所有的观察者
protected:
Subject();
private:
};
class WeatherData:public Subject
{
public:
WeatherData();
~WeatherData();
void Register(Observer* obv);//注册对象
void Remove(Observer* obv);
void Notify();//当主题改变时,用这个方法通知所有的观察者
void measurementsChanged();
void setMeasurements(float temperature,float humidity,float pressure);
protected:
private:
list* _obvs; //保存注册的观察者
float temperature;
float humidity;
float pressure;
};
#endif
#include "Subject.h"
#include "Observer.h"
#include
#include
using namespace std;
Subject::Subject()
{
}
Subject::~Subject()
{
}
void Subject::Register(Observer *obv)
{
}
void Subject::Remove(Observer *obv)
{
}
void Subject::Notify()
{
}
WeatherData::WeatherData()
{
_obvs=new list;
}
WeatherData::~WeatherData()
{
}
void WeatherData::Register(Observer *obv)
{
if(obv!=NULL)
_obvs->push_front(obv);
}
void WeatherData::Remove(Observer *obv)
{
if(obv!=NULL)
_obvs->remove(obv);
}
void WeatherData::Notify()
{
list::iterator it;
it=_obvs->begin();
for(;it!=_obvs->end();it++)
{
(*it)->Update(this->temperature,this->humidity,this->pressure);
}
}
void WeatherData::measurementsChanged()
{
Notify(); //数值更新,通知观察者
}
void WeatherData::setMeasurements(float temperature, float humidity, float pressure)
{
this->temperature=temperature;
this->humidity=humidity;
this->pressure=pressure;
measurementsChanged();
}
//Observer.h
#ifndef _OBSERVER_H_
#define _OBSERVER_H_
#include "Subject.h"
#include
using namespace std;
typedef string State;
class Observer
{
public:
virtual ~Observer();
virtual void Update(float temperature,float humidity,float pressure)=0;
};
class DisplayElement
{
public:
virtual ~DisplayElement();
virtual void display()=0;
};
/*当前状态公告板,实现Observer接口,所以可以从WeatherData对象中获取改变*/
/*规定所有的公告板必须实现DisplayElement接口*/
class CurrentConditionDisplay:public Observer,public DisplayElement
{
public:
CurrentConditionDisplay(Subject *sub);
~CurrentConditionDisplay();
void Update(float temperature,float humidity,float pressure);
void display();
private:
Subject *sub;
float temperature;
float humidity;
};
#endif
#include "Subject.h"
#include "Observer.h"
#include
#include
using namespace std;
//typedef string state;
Observer:: ~Observer()
{
}
DisplayElement::~DisplayElement()
{
}
CurrentConditionDisplay::CurrentConditionDisplay(Subject *sub)
{
this->sub=sub;
sub->Register(this);
}
CurrentConditionDisplay::~CurrentConditionDisplay()
{
sub->Remove(this);
if(sub!=0)
delete sub;
}
void CurrentConditionDisplay::Update(float temperature,float humidity,float pressure)
{
this->temperature=temperature;
this->humidity=humidity;
display();
}
void CurrentConditionDisplay::display()
{
cout<<"Current condition: "<temperature<<"F degrees and "<humidity<<"% humidity"<
#include "Subject.h"
#include "Observer.h"
#include
using namespace std;
int main(int argc,char* argv[])
{
WeatherData *weatherData=new WeatherData(); //建立气象站
CurrentConditionDisplay *currentDisplay=new CurrentConditionDisplay(weatherData);//建立一个公告板,并注册一个观察者Observer,加入其中
weatherData->setMeasurements(80,65,65.4f);//气象站数据变化
weatherData->setMeasurements(81,78,65.4f); //setMeasurements调用Notify()通知所有的公告板更新数据并显示调用Update()函数,而公告板重载Observer的Update()
//从而达到所有的公告板随着weatherData对象即气象站的数据而更新显示
if (NULL != weatherData)
delete weatherData;
return 0;
}