callback与signal/slot是曾经在Windows客户端项目中大规模使用过的解耦利器,常用于UI层/逻辑层解耦,两个功能模块间搭建桥梁。两个的源码分别来自不同的开源库,我稍作过修改,由于源码有点长,不在这里贴了,源码和文档打包在我的资源里了。
callback与signal/slot设计目的、使用场景相同,但设计思想迥异,推荐看一下两者的源码,尤其是callback源码。几个月前总结的,拿出来当时做的笔记。
callback结构图:
signal/slot结构图:
class has_slots
void signal_connect(_signal_base<mt_policy>* sender)
void signal_disconnect(_signal_base<mt_policy>* sender)
sender_set m_senders;
class _signal_base1 : public _signal_base<mt_policy>
typedef std::list<_connection_base1<arg1_type, mt_policy> *> connections_list;
class signal1 : public _signal_base1<arg1_type, mt_policy>
template<class desttype>
void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type))
使用对比
callback | sigslot | |
实现方式 | 链式响应,只维护着一个CallbackAction,有时候这个action是一个CallbackMethodAction,有时候是CallbackForkAction,action是引用计数的,CallbackForkAction里有若干个callback,当一个Callback被执行,会引起链式响应。 | signal维护着一个connect对象链表。 |
被绑定函数所在的类行为 | 如果被绑定体的对象先于signal析构,易导致崩溃。 | 需要将has_slot<>作为基类,因为has_slot<>类维护着signal/slot关系,所以当被绑定体对象析构时候会解除关系,避免了崩溃。 如果复制类对象,类对象的副本也继续响应已经绑定的信号。因为has_slot<>的拷贝构造函数将signal/slot关系也复制了一份。 |
绑定/解除 | 一个callback可以绑定多个响应函数。 只能单向解除绑定,只能callback方解除绑定(调用Clear方法),被绑定者不能解除绑定。 Clear方法里将action引用计数减1,不管是否为0,都将自身action设为null。一旦调用Clear方法等于解除了Callback自身所有的绑定。不能只解除指定的被绑体。 |
一个callback可以绑定多个响应函数。 可以双向解除绑定,即signal方可以解除绑定,slot方也可以解除绑定。 |
被绑定函数的参数个数 | 最多支持4个 | 最多支持8个 |
当类的方法体被const修饰时。 | 支持 | 编译报错误 |
备注:
C++11增加了可变参数的模板,若编译器支持这个特性,重写一遍callback和sigslot能减少很多代码量。