设计模式之观察者模式

何为观察者模式?

        在程序设计中经常会建立对象与对象,或者类与类之间的依赖关系,即当某一个对象发出通知或者发生变化的时候,会通知与他有关联的其他全部对象,就像在路口,当红灯变绿灯后,行人与汽车都会作出动作,实现一对多的联系。

代码:

        做一个小小例子,玩游戏的家族频道,一人发言,所有同家族的成员都能收到消息,然后不同家族的成员无法收到消息,然后加入家族后可以收到消息,退出家族后收不到消息。

        首先定义一个玩家属性:玩家自己的ID,玩家的昵称,玩家的所属家族,玩家的发言函数,收到对面玩家发言的函数。

class Fighter
{
public:
	Fighter(int tmpID,string tmpName):m_iFamilyID(tmpID), m_sPlayerName(tmpName){
		m_iFamilyID = -1;                   //表示未加入任何家族
	}
	~Fighter() {}

public:
	void setFamilyID(int tmpID){
		m_iFamilyID = tmpID;
	}
	int getFamilyID() {
		return m_iFamilyID;
	}

	void sayWords(string tmpContent, Notifier* notifier)
	{
		notifier->notify(this, tmpContent);
	}

	//写成虚函数,方便子类覆盖
	virtual void notifyWords(Fighter* talker, string tmpContent)
	{
		//显示信息
		cout << "玩家:" << m_sPlayerName << " 收到了玩家:" << talker->m_sPlayerName << "发送的聊天消息:" << tmpContent << endl;
	}

private:
	int m_iPlayerID;           //玩家ID
	string m_sPlayerName;      //玩家姓名

	int m_iFamilyID;           //家族ID
};

        定义一个通知器类:用于管理玩家家族列表,例如加入成员,移除成员,和发言。

class Notifier
{
public:
	virtual void addToList(Fighter* player) = 0;         //父类使用纯虚函数,便于多态
	virtual void removeFromList(Fighter* player) = 0;
	virtual void notify(Fighter* talker, string tmpContent) = 0;      //玩家说了某句话
	virtual ~Notifier() {}
};

        多设计两个职业,继承于Fighter。

//战士
class F_Warrior :public Fighter
{
public:
	F_Warrior(int tmpID, string tmpName):Fighter(tmpID, tmpName){}
};

//法师
class F_Mage :public Fighter
{
public:
	F_Mage(int tmpID, string tmpName) :Fighter(tmpID, tmpName) {}
};

        聊天信息通知器设计聊天通知器,实现家族的加入,移除。

class talkNotifier :public Notifier
{
public:
	//将玩家加入到家族列表
	virtual void addToList(Fighter* player)
	{
		int tmpfamilyid = player->getFamilyID();
		if (tmpfamilyid != -1){           //表示已经加入了某个家族
			auto iter = m_familyList.find(tmpfamilyid);     //在全部家族列表中找是不是存在该家族
			if (iter != m_familyList.end()){
				//该家族ID已经存在  直接将玩家加入到该家族中
				iter->second.push_back(player);
			}
			else {
				list<Fighter* >tmpplayerlist;  //创建一个家族
				m_familyList.insert(make_pair(tmpfamilyid, tmpplayerlist)); //然后将家族加入家族列表
				m_familyList[tmpfamilyid].push_back(player);  //并将该玩家设置成家族中成员
			}
		}
	}
	//将玩家移除家族列表
	virtual void removeFromList(Fighter* player)
	{
		int tmpfamilyid = player->getFamilyID();
		if (tmpfamilyid != -1){
			auto iter = m_familyList.find(tmpfamilyid);
			if (iter != m_familyList.end()){
				m_familyList[tmpfamilyid].remove(player);   //根据key值家族id移除player
			}
		}
	}
	//家族中某个玩家说了句话,将调用该函数,进行通知其他玩家
	virtual void notify(Fighter* talker, string  tmpContent)
	{
		int tmpfamilyid = talker->getFamilyID();
		if (tmpfamilyid != -1)
		{
			auto itermap = m_familyList.find(tmpfamilyid);
			if (itermap != m_familyList.end()) {  //遍历该家族的全部成员
				for (auto iterlist = itermap->second.begin(); iterlist != itermap->second.end(); ++iterlist) {
					(*iterlist)->notifyWords(talker, tmpContent);
				}
			}
		}
	}

private:
	map<int, list<Fighter*>>m_familyList;   //key 表示家族id  value 表示家族中的成员列表list
};

        在main函数中调用看看结果:

#include <iostream>
using namespace std;
#include "Observer.h"

int main()
{
	Fighter* play01 = new F_Warrior(10, "张三");
	play01->setFamilyID(100);
	Fighter* play02 = new F_Warrior(20, "李四");
	play02->setFamilyID(100);
	Fighter* play03 = new F_Mage(30, "王五");
	play03->setFamilyID(100);
	Fighter* play04 = new F_Mage(40, "赵六");
	play04->setFamilyID(200);

	//创建通知器
	Notifier* ptalkNotify = new talkNotifier();

	//将玩家加入家族
	ptalkNotify->addToList(play01);
	ptalkNotify->addToList(play02);
	ptalkNotify->addToList(play03);
	ptalkNotify->addToList(play04);

	//玩家发言
	play01->sayWords("全体起立,准备战斗",ptalkNotify);

	cout << "王五不想再收到其他成员信息---------------------------------------" << endl;
	//移除王五
	ptalkNotify->removeFromList(play03);

	play02->sayWords("听从首领指挥,准备战斗", ptalkNotify);

	//释放资源
	delete play01;
	delete play02;
	delete play03;
	delete play04;

	return 0;
}

        运行结果为:

UML图:

总结:

        这个小游戏中主要用到两个容器,使用list容器管理家族成员,使用map容器管理家族,那么每次收发消息的时候,就遍历list容器,挨个调用函数,创造或者注销家族就在map容器中进行,每创建一个家族,就会对应创建家族list,便于管理。

        观察者模式也被称作“发布-订阅”模式,只有提前订阅的人(在同一个list中)才能接收到发布者发布的消息。整个过程即为,发布者发布消息,通知器收到消息开始找订阅者,然后挨个给订阅者发送消息(即调用订阅者的成员函数)。

学习案例来源:《C++新经典设计模式》 王建伟编著

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值