C++11 不使用继承实现观察者模式的方法 注册模板参数

3 篇文章 0 订阅
3 篇文章 0 订阅

观察者模式

观察者模式其实是最常见的设计模式,在工程中很常见;
C++中,同一线程中的不同类之间的消息总需要传递,传递方式就是注册一个回调函数(其实就是个类),当数据更新后,触发回调函数(注册类中的函数)。

//被观察者(需要把数据传出去):
class object
{
	void register(observer* person)
	{
		memeber.insert({1,person}); 
	}
	void notifyObserver()
	{
		for(auto it:member)
		{
			it.second->onListern();
		}
	}
	private:
	map<int,observer> member;
}
//观察者
class observer
{
	onListern()
	{
		cout<<"deal data"
	}
}
可以看出来观察者模式很好用,数据传递到onListerner(),但是现在有个需求就是需要onlisterner()带有参数输入,那就要多写几个重载函数。
class observer
{
	onListern(int type,void* data)
	{
		cout<<"deal data1"
	}
	onListern(int type,void* data,int len)
	{
		cout<<"deal data2"
	}
}
  • 需求变更

    现在又一个新需求,就是新增了10个观察者,需要创建一个Observer基类,那就要再写10个类继承基类。

  • 需求再次增加

    然后又有新需求,观察者的数据需要传出去,也成为被观察者;

  • 需求太多之后,类的数量成倍增加,还难以追踪

    综上,传统的观察者模式还是有着参数不可变以及继承关系爆炸的问题,这两个问题目前看影响不大,但是放在工程中,如果不是代码本人阅读,通知链过长过于宽,就很难记得住代码流程。
    所以结合C++11 新特性,其实观察者模式完全可以被函数指针(std::function)来代替,listen函数的参数可以使用可变参数语法来设计

先写一个简单的,只是使用std::function绑定观察者中的listen函数

class newobserver
{
	onlistern(int type,void* data)
	{
		cout<<"new observer"
	}
}
class newobject
{
	void register(std::function<void(int,int)> fun)
	{
		static key++;
		m_member.emplace(key,fun);
	}
	void notify(int a ,int b)
	{
		for(auto it:m_member)
		{
			it.second(a,b);
		}
	}
	map<int ,std::function<void(int,int)> >m_member;
}
main.cpp

int main()
{
	newobserver  *myobserver = new newobserver;
	auto fun = std::bind(&newobsever::onlistern,myobserver,std::placeholders::1,placeholders::2)

	newobject *myobject = new newobject;
	myobject->register(fun);
	myobject->notify(333,444);
}
  • 利用类模板

    再写个复杂点的,上可变参数,C++11直接可以使用可变参数模板的语法,在此之前先上模板练练手,std:function<void(int,int)> 改用模板

template <typename FuncObserver>
class newObject
{
	void register(FuncObserver fun)
	{
		m_memeber.emplace(key,fun)
	}
	void notify(int a)
	{
		for(auto it:m_member)
		{
			it.second(a);
		}
	}
}
main
{
	newObject myobject;
	newObsever myobsever;

	std::fucntion<void(int)> fun = bind(&newobsever::onlister,&myobsever,::1,::2)
	myobject.register(fun);
	myobject.notify(33333);
}
  • 更换为可变参数模板,其实这个在工程中不适用,容易带来未知的问题,不如先TO DO吧

  • 又来一个需求

    原来的object的类不能变,但是需求注册另外一类观察者dog,而dog本身是动物不是人,应该继承于animal类,不是一种I Observer类,没办法,强行使用双重继承,才能调用原本的object::register函数,这种是在工程中非常常见的需求,增加监听者,如果换乘上述的使用类函数,就可以避免双重继承。


class dogpublic IObserver public IAnimal
{

}
class object
{
	void register(observer* person)
	{
	 
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值