觀察者模式:
定義對象間的一種一對多的依賴關系,當一個對象的狀態發生變化時,所有依賴它的對象都得到通知並被自動更新。
它有四種角色:
主題(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

1 #include "stdafx.h" 2 #include "Observer.h" 3 #include "Subject.h" 4 5 UniversityStudent::UniversityStudent(Subject* subject) 6 { 7 if (NULL != subject) 8 { 9 this->subject = subject; 10 } 11 else 12 { 13 return; 14 } 15 16 subject->addObserver(this); 17 } 18 void UniversityStudent::hearTelephone(string heardMess) 19 { 20 std::cout << "I am a university student" << std::endl; 21 std::cout << "I hear message is " << heardMess << std::endl; 22 return; 23 } 24 25 HaiGui::HaiGui(Subject* subject) 26 { 27 if (NULL != subject) 28 { 29 this->subject = subject; 30 } 31 else 32 { 33 return; 34 } 35 subject->addObserver(this); 36 } 37 38 void HaiGui::hearTelephone(string heardMess) 39 { 40 std::cout << "I am a HaiGui" << std::endl; 41 std::cout << "I hear message is " ; 42 cout << heardMess << endl; 43 return; 44 }
最后一個測試的文件:
#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是虛基類,無法實例化。