何时使用信号和槽,何时不使用
我们使用的 Qt 提供了信号和槽,我觉得这非常方便。然而,能力越大,责任越大,我认为这个功能也很容易被滥用。
是否有信号槽使用的最佳实践?我很难以这种方式找到一些一般准则。一些问题(我有明确的意见,但并非我团队的所有成员都同意):
- 可以使用信号来报告错误吗?
- 可以假设信号将被处理吗?
- 信号可以用来发起行动吗?例如,
signal displayInfoScreen()
必须由显示信息屏幕的槽来处理。
关于何时应该/不应该使用信号的任何其他意见非常欢迎!
We're using Qt that offers signals and slots which I find really convenient. However, with great power comes great responsibility and I think it's very easy too misuse this feature.
Are there any best-practices for signal-slot usage? I'm having a hard time to find some general guidelines in this manner. Some questions (I have clear opinions about, but that not all members of my team agree with):
- Is it ok to use signals to report errors?
- Is it ok to assume that a signal will be handled?
- Can signals be used to initiate actions? E.g.
signal displayInfoScreen()
must be handled by a slot that shows an info screen.
Any other opinions on when signals should/shouldn't be used are very welcome!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
信号和槽非常强大,因为它可以解耦对象。正如前面所回答的,您不能假设信号已连接插槽。
基于信号/槽的设计的一个主要缺点是,您可以很容易地跟踪所实现的逻辑,因为对象的一个操作可以触发连接到发出的信号的任何其他对象的其他操作。更容易产生不需要的副作用、递归调用等。
Signals and slots are powerful because decouples objects. You can't assume that a signal has a slot connected, as previously answered.
A major drawback of signal/slot based design is that you can very easy loose track of the logic you implemented, since one action of an object can trigger other actions of any other object that connected to a signal emitted. It is much easier to have unwanted side effects, recursive calls, etc.
是的,例如,参见 QFtp,其中完成信号携带状态。它不携带实际的错误,仅携带发生错误的信息。
不。但是,发送者永远不能假设您的特定应用程序可以依赖它。例如,代表 File - New 的 QAction 需要经过处理才能使应用程序正常工作,但 QAction 对象并不关心。
再说一遍,是的,例如 QAction 对象。但如果您希望能够重用组件,则必须小心确保实际的类不依赖于它。
Yes, for instance, see QFtp, where the done signal carries a status. It does not carry the actual error, just information that an error has occured.
No. The sender can never assume that, however, your particular application can depend on it. For instance, the QAction representing File - New needs to be handled for the application to work, but the QAction object couldn't care less.
Again, yes, for instance the QAction object. But if you want to be able to reuse components, you must be careful to ensure that the actual class does not depend on it.
不,不是。信号是一种“一劳永逸”的东西。谁连接到信号以及它做什么不应该是发射器关心的。
No it's not. Signals are fire-and-forget type of things. Who connects to a signal and what it does should not be the emitter's concern.
是的,但我通常会视具体情况而定。如果错误可能异步发生,那么指示这种情况的信号绝对是正确的。如果错误仅在客户端代码调用某个函数时发生,则错误应该出现在该函数的响应中,而不是作为信号。然而,存在多种介于两者之间的情况,可以根据具体情况进行处理。
此外,信号槽机制可以使跨线程通信更容易(这很可能被认为是异步情况),我将使用它们来实现此目的(错误或没有)。
信号(从哲学上讲)旨在表明某些事情已经发生。正如其他人所指出的,假设信号将与一个槽匹配,甚至仅与另一个槽匹配,都不是一个好主意。
信号可用于发起行动,但可能不是以您思考的方式。该信号表明 foo 已经发生。如果监视类的代码决定当 foo 发生时,应该显示一个对话框,然后使用该信号来启动该操作。但是,发出信号的类通常不负责确保发生正确的操作,因为它不负责执行该操作。 (如果是,那么它应该是同一类的一部分,并且不需要信号。)
Yes, but I would generally make this situation-dependent. If the error might occur asynchronously, then a signal to indicate such is definitely proper. If the error only occurs when client code calls one certain function, then the error should be in the response from that function, not as a signal. However, there are a wide array of situations in between that might be done on a case-by-case basis.
Also, signal-slot mechanisms can make cross-thread communication easier (which might well be considered the asynchronous case), and I will use them for that purpose (error or no).
Signals are (philosophically) designed to indicate that something has happened. As others have indicated, it's never a good idea to assume that a signal will be matched with a slot, or even with just one other slot.
Signals can be used to initiate actions, but probably not in the way you are thinking. The signal indicates that foo has happened. If the code monitoring your class decides that when foo happens, a dialog should be shown, then the signal was used to initiate that action. However, it's generally not the responsibility of the class emitting the signal to ensure that the proper action occurs, because it is not responsible for doing that action. (If it was, then it should be part of the same class, and no signal would be needed.)
信号/槽(也称为事件)是消除对象之间耦合的好方法。
例如,它们没有了解模型如何工作以及模型何时更改的视图,而是“监听”模型。模型负责说明何时发生变化、发生了什么变化。
活动的问题在于当您根据客户要求设计活动时。例如,您不应该有信号
displayInfoScreen
因为它假设了有关使用此信号的对象的某些信息。相反,它应该是infoChanged
并且InfoScreenDisplayer
监听此信号以将其显示在屏幕上。如果需要,您可以稍后添加一个InfoTweeterPoster
,以便在 Tweeter 发生变化时在 Tweeter 上发布信息。Signals/slots (also called events) are a good way to remove coupling between objects.
For example, instead of having views that understand how the model works, and when the model changes, they "listen" to the model. The model is responsible of saying when it changes, what changes.
The problem with events is when you design your events with client requirements. For example, you should not have a signal
displayInfoScreen
because it assumes something about objects using this signal. Instead, it should beinfoChanged
and theInfoScreenDisplayer
listens to this signals to display it on screen. If you need, you could add later aInfoTweeterPoster
that post the info on Tweeter whenever they change.