所以我开始学习Qt 4.5并发现Signal / Slot机制有所帮助。但是,现在我发现自己正在考虑两种类型的架构。
这是我要使用的那个
class IDataBlock
{
public:
virtual void updateBlock(std::string& someData) = 0;
}
class Updater
{
private:
void updateData(IDataBlock &someblock)
{
....
someblock.updateBlock(data);
....
}
}
注意:内容代码为简洁起见。
现在有信号我可以
void Updater::updateData()
{
...
emit updatedData(data);
}
这更干净,减少了界面的需要,但我应该这样做只是因为我可以吗?第一个代码块需要更多的输入和更多的类,但它显示了一种关系。使用第二块代码,一切都更“无形”。哪一个更可取,如果是逐案的,那么指导原则是什么?
答案 0 :(得分:9)
发送信号需要花费很少的开关和一些额外的函数调用(取决于连接的内容和方式),但开销应该是最小的。
信号的提供者无法控制其客户是谁,即使他们在发出返回的时间内实际上都获得了信号。
这非常方便并且允许完全解耦,但是当执行顺序很重要或者想要返回某些内容时也会导致问题。
永远不要传递指向临时数据的指针(除非你确切地知道你在做什么,即便如此......)。如果必须,传递成员变量的地址 - Qt提供了一种方法来延迟对象的破坏,直到处理完所有事件后。
信号也可能要求事件循环运行(除非我认为连接是直接的)。
总的来说,它们在事件驱动的应用程序中非常有意义(实际上,如果没有它们,很快就会变得非常烦人)。
如果您已在项目中使用Qt,请务必使用它们。如果对Qt的依赖是不可接受的,那么boost也有类似的机制。
答案 1 :(得分:3)
还有另一个区别。 #1与IDataBlock接口硬连接,Updater类需要知道“someblock”。 #2可以通过连接呼叫(或多个,包括断开连接)进行后期耦合,从而实现更加动态的方法。 #2就像一条消息(想想Smalltalk / ObjC)而不是一个电话(想想C / C ++)。消息也可以进行多次调度,这需要在#1中实现该功能。
我的偏好是利用信号/插槽由于它们的灵活性,除非代码性能或需要立即返回数据不允许它(或者不希望依赖于Qt)。
答案 2 :(得分:2)
这两种形式似乎相似。从功能上讲,这是事实。在实践中,您正在解决一个更大的问题。在这些情况下,外部环境会导致这两种解决方案不相同。
一个常见的情况是找出源和汇之间的关系。他们甚至互相认识吗?在你的第一个例子中,updateData()需要传入接收器。但是如果触发器是GUI按钮[更新数据]怎么办?按钮是通用组件,不应该知道IDataBlock。
解决方案当然是将m_someblock成员添加到Updater。按钮现在将更新Updater中的任何成员。但这真的是你想要的吗?