浅谈C++下观察者模式的实现

为什么要有观察者模式

想象一个场景,有一只猫和一群老鼠,当猫出现的时候,每一只老鼠都要逃跑

用最简单的方法实现一个去模拟这一个过程

#include<iostream>

class Mouse_1
{
	public:
		void CatCome()
		{
			std::cout<<"Mouse_1 Run"<<std::endl;	
		}
};

class Mouse_2
{
	public:
		void CatCome()
		{
			std::cout<<"Mouse_2 Run"<<std::endl;	
		}
};

class Cat
{
	public:
		void IamCome()
		{
			std::cout<<"Cat Come!!!"<<std::endl;	
			mouse_1.CatCome();
			mouse_2.CatCome();
		}
	private:
		Mouse_1 mouse_1;
		Mouse_2 mouse_2;
};

int main()
{
	Cat cat;
	cat.IamCome();
	return 0;
}

执行后:

 这么写的话,如果要多增加一只老鼠的话,那么就得把cat的类改为

class Cat
{
	public:
		void IamCome()
		{
			std::cout<<"Cat Come!!!"<<std::endl;	
			mouse_1.CatCome();
			mouse_2.CatCome();
			mouse_3.CatCome();
		}
	private:
		Mouse_1 mouse_1;
		Mouse_2 mouse_2;
		Mouse_3 mouse_3;
};

这样的话每次修改都得修改Cat这个类,不是很方便,那么有没有一种模式可以不用修改这个类去实现添加老鼠的功能,那么就有了观察者模式

观察者模式的实现

首先我们需要定义一个接口,所有的老鼠继承这个接口:

class MosueInterface
{
	public:
		virtual void CatCome()=0;
		virtual ~MosueInterface(){}
};

接着定义两只“mouse”:

class Mouse_1 : public MosueInterface
{
	public:
		void CatCome() override
		{
			std::cout<<"Mouse_1 Run"<<std::endl;	
		}
};

class Mouse_2 : public MosueInterface
{
	public:
		void CatCome() override
		{
			std::cout<<"Mouse_2 Run"<<std::endl;	
		}
};

接下来就要定义老猫了,首先需要一个vector能存储所有的老鼠:

std::vector<MosueInterface*> mice;

在老猫的方法里面定义添加修改这个vector的方法 :

//向vector中添加老鼠
void Add(MosueInterface* mouse) 
{
	mice.push_back(mouse);
}
//从vector中删除老鼠
void Remove(MosueInterface* mouse) 
{
	std::vector<MosueInterface*>::iterator it = std::find(mice.begin(),mice.end(),mouse);
	if(it!=mice.end())
	{
		mice.erase(it);
	}
}

遍历vector,挨个对老鼠发送“我来了的消息”:

void IamCome() 
{
	std::cout<<"Cat Come!!!"<<std::endl;	
	for(const auto i : mice)
		{
			i->CatCome();
		}
}

老猫的总体定义如下: 

class Cat 
{
	public:
		void Add(MosueInterface* mouse) 
		{
			mice.push_back(mouse);
		}
		
		void Remove(MosueInterface* mouse) 
		{
			std::vector<MosueInterface*>::iterator it = std::find(mice.begin(),mice.end(),mouse);
			if(it!=mice.end())
			{
				mice.erase(it);
			}
		}
		void IamCome() 
		{
			std::cout<<"Cat Come!!!"<<std::endl;	
			for(const auto i : mice)
			{
				i->CatCome();
			}
		}
	private:
		std::vector<MosueInterface*> mice;
};

在main中执行事件:

int main()
{
	Cat cat;
	cat.Add(new Mouse_1);
	cat.Add(new Mouse_2);
	cat.IamCome();
	return 0;
}

整体代码如下

#include<iostream>
#include<vector>
#include<algorithm>

class MosueInterface
{
	public:
		virtual void CatCome()=0;
		virtual ~MosueInterface(){}
};


class Mouse_1 : public MosueInterface
{
	public:
		void CatCome() override
		{
			std::cout<<"Mouse_1 Run"<<std::endl;	
		}
};

class Mouse_2 : public MosueInterface
{
	public:
		void CatCome() override
		{
			std::cout<<"Mouse_2 Run"<<std::endl;	
		}
};

class Cat 
{
	public:
		//向vector中添加老鼠
		void Add(MosueInterface* mouse) 
		{
			mice.push_back(mouse);
		}
		//从vector中删除老鼠
		void Remove(MosueInterface* mouse) 
		{
			std::vector<MosueInterface*>::iterator it = std::find(mice.begin(),mice.end(),mouse);
			if(it!=mice.end())
			{
				mice.erase(it);
			}
		}
		void IamCome() 
		{
			std::cout<<"Cat Come!!!"<<std::endl;	
			for(const auto i : mice)
			{
				i->CatCome();
			}
		}
	private:
		std::vector<MosueInterface*> mice;
};

int main()
{
	Cat cat;
	cat.Add(new Mouse_1);
	cat.Add(new Mouse_2);
	cat.IamCome();
	return 0;
}

执行后:

 这时候猫作为被观察者,老鼠作为观察者,这时候执行“我来了”的事件,就不需要每次都修改执行的代码了,只需要在主函数中添加即可

代码抽象出来

我们这时候想把这个观察者和被观察者抽象出来代码如下:

#include<iostream>
#include<vector>
#include<algorithm>

class MosueInterface
{
	public:
		virtual void CatCome()=0;
		virtual ~MosueInterface(){}
};

class CatInterface{
public:
    virtual void Add(MosueInterface* mouse)=0;
    virtual void Remove(MosueInterface* mouse)=0;
    virtual void IamCome()=0;
    virtual ~CatInterface(){}
};

class Mouse_1 : public MosueInterface
{
	public:
		void CatCome() override
		{
			std::cout<<"Mouse_1 Run"<<std::endl;	
		}
};

class Mouse_2 : public MosueInterface
{
	public:
		void CatCome() override
		{
			std::cout<<"Mouse_2 Run"<<std::endl;	
		}
};

class Cat : public CatInterface
{
	public:
		void Add(MosueInterface* mouse) override
		{
			mice.push_back(mouse);
		}
		
		void Remove(MosueInterface* mouse) override
		{
			std::vector<MosueInterface*>::iterator it = std::find(mice.begin(),mice.end(),mouse);
			if(it!=mice.end())
			{
				mice.erase(it);
			}
		}
		void IamCome() override
		{
			std::cout<<"Cat Come!!!"<<std::endl;	
			for(const auto i : mice)
			{
				i->CatCome();
			}
		}
	private:
		std::vector<MosueInterface*> mice;
};

int main()
{
	Cat cat;
	cat.Add(new Mouse_1);
	cat.Add(new Mouse_2);
	cat.IamCome();
	return 0;
}

在许多设计中,经常涉及多个对象都对一个特殊对象中的数据变化感兴趣,而且这多个对象都希望跟踪那个特殊对象中的数据变化,也就是说当对象间存在一对多关系时,在这样的情况下就可以使用观察者模式。当一个对象被修改时,则会自动通知它的依赖对象。

观察者模式是关于多个对象想知道一个对象中数据变化情况的一种成熟的模式。观察者模式中有一个称作“主题”的对象和若干个称作“观察者”的对象,“主题”和“观察者”间是一种一对多的依赖关系,当“主题”的状态发生变化时,所有“观察者”都得到通知。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值