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