標籤:測試 角色 cheng 轉換 包含 聲明 bsp 觀察 back
觀察者模式:
定義對象間的一種一對多的依賴關係,當一個對象的狀態發生變化時,所有依賴它的對象都得到通知並被自動更新。
它有四種角色:
主題(Subject):一個介面,規定了具體主題需要實現的方法。
觀察者(Observer):也是一個介面,規定了具體觀察者用來更新資料的方法。
具體主題:實現主題介面的一個執行個體,比如本例中的“就業通知中樞”;裡面會維護一個具體觀察者的集合。本文使用STL中的list。
具體觀察者:實現觀察者的一個執行個體,會包含存放主題的引用或者指標。
使用C++實現如下:
包含5個檔案,標頭檔兩個:主題類(Subject.h)觀察者類(Observer.h)
源檔案兩個:主題類(Subject.cpp)觀察者類(Observer.h)
一個測試檔案。
//Subject.h
#ifndef _SUBJECT_H_#define _SUBJECT_H_#include "Observer.h"#include <list>#include <string>using namespace std;class Observer;//注意C++中雖然包含了標頭檔這裡也需要聲明typedef list<Observer*> myList;class Subject{public:Subject(){}virtual ~Subject(){}virtual void addObserver(Observer* o) = 0;virtual void deleteObserver(Observer* o) = 0;virtual void notifyObservers() = 0;};class SeekJobCenter : public Subject{public:SeekJobCenter();~SeekJobCenter(){}void addObserver(Observer* o);void deleteObserver(Observer* o);void notifyObservers();void giveNewMessage(string str);private:string mess;bool changed;myList personList;};#endif
//Subject.cpp
//具體的主題#include "stdafx.h"#include "Subject.h"#include "Observer.h"#include <list>SeekJobCenter::SeekJobCenter(){mess = "";changed = false;}void SeekJobCenter::addObserver(Observer* o){list<Observer*>::iterator it;//判斷原始維護的list中是否存在添加的對象it = find(personList.begin(), personList.end(), o);if (it == personList.end())//不存在{personList.push_back(o);}return;}void SeekJobCenter::deleteObserver(Observer* o){list<Observer*>::iterator it;it = find(personList.begin(), personList.end(), o);if (it != personList.end())//存在{personList.remove(*it);delete(*it);}return;}void SeekJobCenter::notifyObservers(){list<Observer*>::iterator it;if (changed){for (it = personList.begin(); it != personList.end(); ++it){(*it)->hearTelephone(mess);}changed = false;}return;}void SeekJobCenter::giveNewMessage(string str){if (0 == strcmp(str.c_str(), mess.c_str())){changed = false;}else{mess = str;changed = true;}return;}
//Observer.h
#ifndef _OBSERVER_H_#define _OBSERVER_H_#include <string>#include <iostream>#include <list>#include "Subject.h"using namespace std;class Subject;/*觀察者基類*/class Observer{public:Observer(){};virtual ~Observer(){};virtual void hearTelephone(string heardMess) = 0;};class UniversityStudent : public Observer{public:UniversityStudent(Subject* subject);virtual ~UniversityStudent(){};void hearTelephone(string heardMess);private:Subject* subject;};class HaiGui : public Observer{public:HaiGui(Subject *subject);virtual ~HaiGui(){};void hearTelephone(string heardMess);private:Subject *subject;};#endif
//Observer.cpp
#include "stdafx.h"#include "Observer.h"#include "Subject.h"UniversityStudent::UniversityStudent(Subject* subject){if (NULL != subject){this->subject = subject;}else{return;}subject->addObserver(this);}void UniversityStudent::hearTelephone(string heardMess){std::cout << "I am a university student" << std::endl;std::cout << "I hear message is " << heardMess << std::endl;return;}HaiGui::HaiGui(Subject* subject){if (NULL != subject){this->subject = subject;}else{return;}subject->addObserver(this);}void HaiGui::hearTelephone(string heardMess){std::cout << "I am a HaiGui" << std::endl;std::cout << "I hear message is " ;cout << heardMess << endl;return;}
最後一個測試的檔案:
#include "stdafx.h"#include "Observer.h"#include "Subject.h"int _tmain(int argc, _TCHAR* argv[]){SeekJobCenter *center = new SeekJobCenter();UniversityStudent *chengchaolee = new UniversityStudent(center);HaiGui *haigui = new HaiGui(center);center->giveNewMessage("I need a cook");center->notifyObservers();center->giveNewMessage("I need a xxxx");center->notifyObservers();delete center;delete chengchaolee;delete haigui;return 0;}
定義兩個具體的觀察者,並且以具體主題作為參數,代表它觀察的對象,然後當主題推送資料時,觀察者就會收到訊息,即“推資料”的方式,當然還有一種觀察者模式採用的是拉資料,即由觀察者自己定義需要什麼資料,主題在notify的時候並不傳遞參數而是在觀察者更新資料時,將Subject向下轉換為具體Subject,從而擷取其中相應的資料,這種方式叫做“拉資料”。
值得注意的是,C++在實現的時候,採用list儲存具體觀察者,需要使用list<Observer*>類型,即使用指標。不然會編譯不通過,因為Observer是虛基類,無法執行個體化。
(一)觀察者模式-C++實現