Head-first设计模式(二)——观察者模式(Observer Pattern)
2012-05-06 17:16
489 查看
一、定义
观察者模式在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。二、要点
观察者模式定义了对象之间的一对多关系主题(可观察者)用一个共同的接口来更新观察者
可观察者不知道观察者的细节,只知道观察者实现了观察者接口
使用此模式时,你可从被观察者处推(push)或者拉(pull)数据(然而,推的方式被认为更“正确”)
有多个观察者时,不可以依赖特定的通知次序
三、类图
四、代码
1. 采用“推(push)”的方式:class Subject { public: Subject(){}; virtual ~Subject(){}; void registerObserver(Observer *o); void removeObserver(Observer *o); virtual void notifyObservers() = 0; protected: vector<Observer*> observers; }; void Subject::registerObserver(Observer *o){ observers.push_back(o); } void Subject::removeObserver(Observer *o){ remove(observers.begin(), observers.end(), o); } class ConcreteSubject : public Subject { public: ConcreteSubject():changed(false),data1(0),data2(0.0),data3(""){}; ~ConcreteSubject(){}; void notifyObservers(); bool isChanged(); void setChanged(); void changeData(int d1, float d2, string d3); void dataChanged(); private: bool changed; int data1; float data2; string data3; }; void ConcreteSubject::notifyObservers(){ if(isChanged()) { for(vector<Observer*>::iterator it = observers.begin(); it != observers.end(); ++it){ it->update(data1, data2, data3); } changed = false; } } void ConcreteSubject::changeData(int d1, float d2, string d3){ data1 = d1; date2 = d2; data3 = d3; dataChanged(); } void ConcreteSubject::dataChanged(){ setChanged(); notifyObservers(); } void ConcreteSubject::setChanged(){ changed = true; } bool ConcreteSubject::isChanged(){ return changed; } class Observer { public: Observer(){} ~Observer(){} virtual void update(int d1, float d2, string d3) = 0; }; class ConcreteObserver : public Observer { public: ConcreteObserver(Subject *pSubject); ~ConcreteObserver(){} void update(int d1, float d2, string d3); void display(); void unregister(); private: Subject *pSubject; //为了以后取消注册方便,保留此引用 int data1; float data2; }; ConcreteObserver::ConcreteObserver(Subject *pSubject){ if(pSubject){ this.pSubject = pSubject; this.pSubject.registerObserver(this); } } void ConcreteObserver::unregister(){ if(pSubject){ this.pSubject.removeObserver(this); } } void display(){ printf("data1:%d, data2:%f\n", data1, data2); } void update(int d1, float d2, string d3){ data1 = d1; data2 = d2; }
2. 采用“拉(pull)”的方式
class DataObj{ }; class ConcreteSubjectDataObj : public DataObj { public: int data1; float data2; string data3; }; class Subject { public: Subject():type("Subject"){}; virtual ~Subject(){}; void registerObserver(Observer *o); void removeObserver(Observer *o); virtual void notifyObservers() = 0; void getType(){return type;} protected: vector<Observer*> observers; string type; }; void Subject::registerObserver(Observer *o){ observers.push_back(o); } void Subject::removeObserver(Observer *o){ remove(observers.begin(), observers.end(), o); } class ConcreteSubject : public Subject { public: ConcreteSubject():changed(false),type("ConcreteSubject"){ dataObj.data1 = 0; dataObj.data2 = 0.0; dataObj.data3 = ""; }; ~ConcreteSubject(){}; void notifyObservers(int type = 0); // 0 for push, 1 for pull bool isChanged(); void setChanged(); void changeData(ConcreteSubjectDataObj *pData); void dataChanged(); //a group of getter method int getData1(){return pData->data1;} float getData2(){return pData->data2;} string getData3(){return pData->data3;} private: bool changed; ConcreteSubjectDataObj dataObj; }; void ConcreteSubject::notifyObservers(int type){ if(isChanged()) { ConcreteSubjectDataObj *pDataObj = (0 == type) ? &dataObj : NULL; for(vector<Observer*>::iterator it = observers.begin(); it != observers.end(); ++it){ it->update(this, pDataObj); } changed = false; } } void ConcreteSubject::changeData(ConcreteSubjectDataObj *pData){ this.dataObj = *pData; dataChanged(); } void ConcreteSubject::dataChanged(){ setChanged(); /* pull */ notifyObservers(1); /** push notifyObservers(0); */ } void ConcreteSubject::setChanged(){ changed = true; } bool ConcreteSubject::isChanged(){ return changed; } class Observer { public: Observer(){} virtual ~Observer(){} virtual void update(Subject *pSubject, DataObj *pDataObj) = 0; }; class ConcreteObserver : public Observer { public: ConcreteObserver(Subject *pSubject); ~ConcreteObserver(){} void update(Subject *pSubject, DataObj *pDataObj); void display(); void unregister(); private: Subject *pSubject; //为了以后取消注册方便,保留此引用 int data1; float data2; }; ConcreteObserver::ConcreteObserver(Subject *pSubject){ if(pSubject){ this.pSubject = pSubject; this.pSubject.registerObserver(this); } } void ConcreteObserver::unregister(){ if(pSubject){ this.pSubject.removeObserver(this); } } void display(){ printf("data1:%d, data2:%f\n", data1, data2); } void update(Subject *pSubject, DataObj *pDataObj){ if(!pSubject->getType().compare("ConcreteSubject")){ data1 = pSubject->getData1(); data2 = pSubject->getData2(); } }
五、疑问解答
1. 关于采用推方式和拉方式推方式:
优点:可以在一次通知中一口气得到所有东西;
缺点:有可能造成只需要一点点数据的类被强迫收到一堆数据;
拉方式:
优点:
需要什么数据就拉什么数据,不会有冗余数据;
当主题增加新状态时,只需要增加相应的getter方法,不需要修改和更新每位观察者的调用
缺点:
被观察者门户大开,不管是注册还是未注册的观察者都能获取被观察者的数据;
有可能需要调用很多次getter方法才能收集到需要的所有数据
六、参考文献
1. Head First设计模式相关文章推荐
- First Head 设计模式之观察者模式(Observer Pattern)
- 设计模式之 观察者模式 the observer design pattern ---------《head first design pattern》
- 《Head First Design Patterns》笔记二:观察者模式(Observer Pattern)
- 【pattern】设计模式(3) - Observer观察者模式
- 我所理解的设计模式(C++实现)——观察者模式(Observer Pattern)
- 设计模式----行为型模式之观察者模式(Observer Pattern)
- 极速理解设计模式系列:2.观察者模式(Observer Pattern)
- .NET设计模式(19):观察者模式(Observer Pattern)
- 设计模式之观察者模式(Observer Pattern)
- 设计模式----行为型模式之观察者模式(Observer Pattern)
- HeadFirst design pattern笔记-观察者模式
- C#设计模式——观察者模式(Observer Pattern)1
- java设计模式——观察者模式(Observer Pattern)
- 设计模式(二)The Observer Pattern 观察者模式
- 深入浅出设计模式-002:观察者模式(Observer Pattern)
- C++设计模式 -> 行为型 -> 观察者模式(Observer Pattern)
- 极速理解设计模式系列:2.观察者模式(Observer Pattern)
- Head First Design Patterns读书笔记及C++版代码(一):观察者(Observer)模式
- C#设计模式-观察者模式(Observer Pattern)[FreeDownload]
- 设计模式之观察者模式(Observer Pattern)