C++ | 观察者模式

目录

一.观察者模式

二.代码实现


一.观察者模式

观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。

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

主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。

如何解决:使用面向对象技术,可以将这种依赖关系弱化。

关键代码:在抽象类里有一个 ArrayList 存放观察者们。

应用实例:假设现在有一名男子怀疑自己被戴了绿帽子,但是他又没有证据,于是他花钱雇佣了一位私家侦探去调查他的老婆,并告诉这位私家侦探如果一有什么动静发生,就立马通知他,好让他采取行动。在这个例子中这位男子就是监听者,而这位私家侦探就是观察者,观察者所要做的事情就是观察某一事件是否发生,如果事件发生了就去通知监听者,而监听者所要做的就是处理事件。

观察者和监听者之间的关系(多对多):

  1. 多个观察者可以为同一个监听者服务。
  2. 一个观察者可以为多个监听者服务。

二.代码实现

#include<iostream>
#include<map>
#include<vector>

class Listener
{
public:
	Listener(std::string name)
		:mname(name) {}
	virtual void handleMessage(int message) = 0;
protected:
	std::string mname;
};
class Listener1 : public Listener
{
public:
	Listener1(std::string name) :Listener(name) {}
	void handleMessage(int message)
	{
		switch (message)
		{
		case 1:
			std::cout << mname << " : 1 " << "has been  solved! " << std::endl;
			break;
		case 2:
			std::cout << mname << " : 2 " << "has been  solved! " << std::endl;
			break;
		default:
			std::cout << mname << " no interested this message!" << std::endl;
			break;
		}
	}
};
class Listener2 : public Listener
{
public:
	Listener2(std::string name) :Listener(name) {}
	void handleMessage(int message)
	{
		switch (message)
		{
		case 2:
			std::cout << mname << " : 2 " << "has been  solved! " << std::endl;
			break;
		case 3:
			std::cout << mname << " : 3 " << "has been  solved! " << std::endl;
			break;
		default:
			std::cout << mname << " no interested this message!" << std::endl;
			break;
		}
	}
};

class Listener3 : public Listener
{
public:
	Listener3(std::string name) :Listener(name) {}
	void handleMessage(int message)
	{
		switch (message)
		{
		case 1:
			std::cout << mname << " : 1 " << "has been  solved! " << std::endl;
			break;
		case 3:
			std::cout << mname << " : 3 " << "has been  solved! " << std::endl;
			break;
		default:
			std::cout << mname << " no interested this message!" << std::endl;
			break;
		}
	}
};

class Oberseve
{
public:
	void notify(int message)//某一事件发生;
	{
		std::map<int, std::vector<Listener*>>::iterator fit = mymap.find(message);
		if (fit != mymap.end())//有感兴趣的监听者 
		{
			std::vector<Listener*>::iterator it = fit->second.begin();//vector迭代器
			while (it != fit->second.end())
			{
				//消息通知    调用对方的接口  
				(*it)->handleMessage(message);
				it++;
			}
		}
		else//没感兴趣的监听者 
		{
			std::cout << "no listener interested this message!" << std::endl;
		}
	}
	void registerMessage(int message, Listener* pl)//让观察者观察某一事件
	{
		std::map<int, std::vector<Listener*>>::iterator fit = mymap.find(message);
		if (fit != mymap.end())//找到了 该事件已经注册  插入监听者集合
		{
			fit->second.push_back(pl);
		}
		else//没找到  map 插入一个关系
		{
			std::vector<Listener*> vec;
			vec.push_back(pl);
			mymap[message] = vec;
		}
	}
private:
	std::map<int, std::vector<Listener*>> mymap;//事件 监听者
};

int main()
{
	Listener1 l1("listener1");
	Listener2 l2("listener2");
	Listener3 l3("listener3");

	Oberseve ob;

	ob.registerMessage(1, &l1);//表示1号监听者对1号事件感兴趣
	ob.registerMessage(2, &l1);//表示2号监听者对1号事件感兴趣
	ob.registerMessage(2, &l2);//表示2号监听者对2号事件感兴趣
	ob.registerMessage(3, &l2);//表示3号监听者对2号事件感兴趣
	ob.registerMessage(1, &l3);//表示1号监听者对3号事件感兴趣
	ob.registerMessage(3, &l3);//表示3号监听者对3号事件感兴趣

	ob.notify(1);//事件1发生
	ob.notify(2);//事件2发生
	ob.notify(3);//事件3发生
	ob.notify(4);//事件4发生
	return 0;
}

在上述代码中,Listener类中的handleMessage(int message)函数,代表处理事件函数,即此时某监听者感兴趣的事件message发生了,监听者会调用这个函数来进行相应的处理。在本例中,我们规定一号监听者listener1只对事件1和事件2感兴趣,二号监听者只对事件2和事件3感兴趣,三号监听者只对事件1和事件3感兴趣。

前面我们讲到过一个监听者可能对多个事件感兴趣,为了描述这一特征,我们使用单映射容器map来存放某一事件和对这一事件感兴趣的监听者,我们用map容器中的键(key)来表示某一事件,用值(value)来表示对这一事件感兴趣的监听者,考虑到监听者可能有多个,我们在用vector容器来存放对某一事件感兴趣的监听者,即这里map容器中的键值对为key:int->value:vector,而vector中存放监听者,即

std::map<int, std::vector<Listener*>> mymap};//事件 监听者

在观察者类Oberseve中有两个成员函数,分别是void notify(int message) 和 void registerMessage(int message, Listener* pl)。我们首先来看

void notify(int message)//某一事件发生;
	{
		std::map<int, std::vector<Listener*>>::iterator fit = mymap.find(message);
		if (fit != mymap.end())//有感兴趣的监听者 
		{
			std::vector<Listener*>::iterator it = fit->second.begin();//vector迭代器
			while (it != fit->second.end())
			{
				//消息通知    调用对方的接口  
				(*it)->handleMessage(message);
				it++;
			}
		}
		else//没感兴趣的监听者 
		{
			std::cout << "no listener interested this message!" << std::endl;
		}
	}

这个函数代表此时message这个事件发生了,这是观察者要干的第一件事就是判断是否有监听者对此时发生的这个事件message感兴趣,于是我们首先使用find函数在map容器中查找是否有键(key)== message的数据。如果有,说明有对这个事件感兴趣的观察者,接着我们就对这个事件感兴趣的所有监听者发送信息(因为对 某一事件感兴趣的监听者可能有多个),也就是调用handleMessage这个借口。如果没有对这个事件感兴趣的监听者(即map容器中不存在键(key)== message 的数据),就不做任何处理。

void registerMessage(int message, Listener* pl)//让观察者观察某一事件
	{
		std::map<int, std::vector<Listener*>>::iterator fit = mymap.find(message);
		if (fit != mymap.end())//找到了 该事件已经注册  插入监听者集合
		{
			fit->second.push_back(pl);
		}
		else//没找到  map 插入一个关系
		{
			std::vector<Listener*> vec;
			vec.push_back(pl);
			mymap[message] = vec;
		}
	}

registerMessage这个函数代表让观察者观察某一事件,并且表明哪些监听者对这个事件感兴趣,假设现在我们给定了某一事件message,我们首先要做的就是判断观察者是否已经观察了这个事件,即判断当map容器中是否存在键(key) ==  message 的数据,如果不存在就将这个事件插入。如果存在就说明观察者已经观察了这一事件,即map容器中已经存在键(key) ==  message 的数据,那么就将其他对这个事件感兴趣的监听者插入(因为可能有多个监听者对同一事件感兴趣的可能)。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要实现观察者模式,首先需要定义一个Observer类,其中包含一个纯虚函数update(),用于接收并处理主题状态的更新。 接下来,创建一个具体的观察者类ConcreteObserver,该类继承自Observer类,并实现update()函数。在该函数中,可以通过调用主题对象的getStatus()函数来获取主题状态的更新,并进行相应的处理。 然后,定义一个主题类Subject,其中包含一个存储观察者对象的容器m_observers。该类提供了添加观察者、删除观察者和通知观察者的功能。在添加观察者时,可以使用m_observers.push_back(observer)将观察者对象添加到容器中;在删除观察者时,可以通过遍历容器找到对应的观察者对象,并使用m_observers.erase(iter)将其从容器中删除;在通知观察者时,通过遍历容器调用每个观察者的update()函数来更新观察者的状态。 这样,就完成了C++实现观察者模式的步骤。通过创建具体的观察者对象并将其添加到主题对象中,当主题状态发生变化时,观察者对象会相应地进行更新。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [设计模式-观察者模式 C++实现](https://blog.csdn.net/u012611878/article/details/72859047)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值