观察者模式(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 <list> #include <string> 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<Observer* >* _obvs; //保存注册的观察者 float temperature; float humidity; float pressure; }; #endif
#include "Subject.h" #include "Observer.h" #include <iostream> #include <list> 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<Observer*>; } 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<Observer*>::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 <string> 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 <iostream> #include <list> 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: "<<this->temperature<<"F degrees and "<<this->humidity<<"% humidity"<<endl; }
#include "Subject.h" #include "Observer.h" #include <iostream> 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; }