比较两个解耦利器:callback vs signal/slot

时间:2021-06-29 00:13:04

callback与signal/slot是曾经在Windows客户端项目中大规模使用过的解耦利器,常用于UI层/逻辑层解耦,两个功能模块间搭建桥梁。两个的源码分别来自不同的开源库,我稍作过修改,由于源码有点长,不在这里贴了,源码和文档打包在我的资源里了。

callback与signal/slot设计目的、使用场景相同,但设计思想迥异,推荐看一下两者的源码,尤其是callback源码。几个月前总结的,拿出来当时做的笔记。


callback结构图:

比较两个解耦利器:callback vs signal/slot


signal/slot结构图:

比较两个解耦利器:callback vs signal/slot

UML画图工具对于复合的类型报告语法错误,sigslog.png上的函数与原型不一致,简单在这里记一下:
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能减少很多代码量。