我已经获得了 C++ 方面的经验,但我是 Qt 方面的新手。我得到了一个真正的项目,由不再在这家公司工作的人开发。我不知道这是否是一个好的做法,我提前为可能不太合适的术语表示歉意:我注意到这个项目实际上充满了我认为不必要的信号/槽对。更准确地说:规定应用程序逻辑的类相互看到,公开一些公共方法来触发所需的过程就足够了,但是,尽管如此,这几乎总是使用信号和槽来实现(我在这里再说一遍) :即使没有来自 GUI 的输入)。鉴于我是 Qt 的新手,这样做是一个很好的做法吗?谢谢。
编辑:我报告的情况不包含来自计时器、线程或其他任何东西的信号。这家伙使用了信号和槽对,就像它是从类(例如 A 类到 B 类)的直接方法调用的替代
过度使用使用信号和槽是一种非常糟糕且不幸的是非常常见的做法。它隐藏了依赖关系,使代码难以调试,并且从长远来看基本上无法维护。不幸的是,许多程序员认为这是一个很好的做法,因为他们实现了“解耦”,这对他们来说似乎是一个圣杯。这是无稽之谈。
我并不是说你根本不应该使用信号和槽。我只是说你不应该过度使用它们。信号和槽是实现的完美工具观察者设计模式的完美工具,以实现“反应式”系统,其中对象对更改其状态的其他对象做出反应。只有这样才是信号和槽的正确使用。几乎所有其他对信号和槽的使用都是错误的。我见过的最极端的情况是通过信号槽连接实现 getter 函数。信号发送对变量的引用,槽用一个值填充它,然后返回到发射器。这太疯狂了!
您如何知道您的信号和槽正确实现了观察者模式?这些是我长期使用 Qt 的经验得出的经验法则:
您会在 GUI 层中看到大量信号槽连接是正常的,这是完全可以的(注意:GUI 层包括视图模型!)。这是因为 GUI 通常是一个反应式系统,其中对象对其他对象或底层的某些变化做出反应。但是您可能会在业务逻辑层中看到更少的信号槽连接(顺便说一句,在许多项目中,业务逻辑是在不使用 Qt 的情况下进行编码的)。
关于命名:我遇到了一种有趣的代码味道。当观察者的公共(!)槽被称为onSomethingHappened()
- 时,强调前缀on
。这几乎总是不良设计和滥用信号和槽的迹象。通常这个槽应该a)设为私有,并且连接应该由观察者建立,或者b)应该重命名为doSomething()
或c)应该重命名并且应该作为正常方法调用,而不是使用信号和槽。
并说明为什么过度使用信号和槽难以维护。从长远来看,有许多潜在的问题可能会破坏您的代码:
要检查我是否没有多个连接或者连接/断开连接是否成功,我正在使用这些我的帮助实用程序https://github.com/vladimir-kraus/qtutils/blob/main/qtutils/safeconnect.h
PS:在上面的文本中,我使用术语“发射器”(发射信号)和“观察者”(观察发射器并接收信号)。有时人们使用“发送者”和“接收者”来代替。我的目的是强调这样一个事实:发射器发出信号时实际上并不知道是否有人接收到它。“发送者”一词给人的印象是您将信号发送给某人,但这正是信号槽过度使用和不良设计的原因。因此,在我看来,使用“发送者”只会导致混乱。通过使用“观察者”,我想强调信号和槽是实现观察者设计模式的工具。
PPS:信号和槽也是 Qt 中线程之间异步通信的完美工具。这个用例可能是我上面描述的原则的极少数例外之一。