首页 > 代码库 > (一)观察者模式-C++实现

(一)观察者模式-C++实现

观察者模式:

    定义对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都得到通知并被自动更新。

它有四种角色:

主题(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++实现