2008-11-23 109 views
13

有人可以用简单的术语解释“信号和插槽”模式吗?什么是信号和插槽?

+1

你是指Qt信号和插槽? – 2008-11-23 20:17:07

+0

一般的模式。维基百科表示助推也是如此。 – JeffV 2008-11-23 20:26:47

回答

18

信号和时隙是解耦发送者(信号)和零个或多个接收者(插槽)的一种方式。假设你有一个系统有事件,你想让这个系统的任何其他部分对这些事件感兴趣。不要将生成事件的代码硬编码到想知道这些事件的代码上,而是使用信号和插槽模式。

当发送者发出一个事件信号(通常通过调用与该事件/信号相关的函数)时,该事件的所有接收者都会被自动调用。这使您可以在程序生命周期内根据需要连接和断开接收器。

由于此问题被标记为C++,因此这里是Boost.Signals库的链接,它有一个更详尽的解释。

4

我假设你在谈论QT的信号和插槽。
这很简单。

一个类的实例可以触发一个信号,另一个类的另一个实例可以在一个槽中捕获该信号。这就像一个函数调用,只是调用函数的人不需要知道谁想接收这个调用。

最好的解释方法是举一个例子。
类QPushButton有一个信号QPushButton :: clicked()。只要按钮被点击,该信号就会被触发。按钮不需要知道谁有兴趣知道点击发生了。它只是触发信号,任何感兴趣的人都可以连接到它。
按钮放置在其中的QDialog事实上有兴趣知道按钮被点击的时间。它有插槽MyDialog :: buttonClicked()。在MyDialog c'tor上,您需要将按钮的click()信号连接()到对话框的buttonClicked()插槽,以便在信号被触发时调用该插槽。

一束更先进的东西:

  • 参数,信号可以有参数和这些参数可以任选地传递给时隙为好。
  • 交叉线程调用 - 如果您正在创建需要交叉线程的信号插槽连接,那么QT会自动缓存信号并将它们排队到正确的线程。例如,当GUI线程需要与工作线程通信时,会自动发生。

Here's more information in QT's documentation.

12

我觉得一个可以描述的信号,最好的插槽,当你作为一个可能的实现车辆的Observer Pattern or Publish/Subscriber Pattern看着他们。在发布方有一个signal,例如buttonPressed(IdType)。无论何时按下按钮,都会调用连接到该信号的所有插槽。插槽在用户端。一个插槽例如可以是sendMail(IdType)

随着事件“按下按钮”,插槽将知道哪个按钮被按下,因为id已被移交。 IdType表示通过发布者和订阅者之间的连接发送的数据的类型。订阅者可能进行的操作是connect(signal, slot),它可以连接buttonPressed(IdType)sendMail(IdType),这样如果按下该按钮,就调用该特定插槽。

这样做的好处是用户(插槽方)不需要关心信号的细节。它只需要连接。因此,在这里我们有大量的松耦合。您可以更改按钮的实现,但插槽的接口仍然相同。

查看Qt Signals/SlotsBoost Signals了解更多信息。

6

想象一下,在您的应用程序中有一个GUI。大多数情况下,控制流程不会是非常线性的,也就是说,您不需要有一个明确的操作序列,就可以让用户与GUI进行交互(如按钮,菜单等)。

这实际上是一个事件驱动模型,可以很好地与信号和插槽模式一起实现。信号是由对象(想象为GUI组件)产生的事件,槽是这些事件的接收器。

下面是一个例子:假设您有一个复选框,在您的编程语言中表示为一个对象。该复选框可能会发生多种情况:可以切换,这也意味着它可以设置或不设置。这些是它可以发出的信号。我们将它们命名为checkboxToggled,checkboxSet和checkboxUnset。正如你所看到的,在这个例子中,当切换时,该复选框将始终发出checkboxToggled信号,但也正好是其他两个信号中的一个,具体取决于状态如何变化。

现在设想有一些其他对象,即一个标签,为了这个例子,它总是作为一个对象存在,但可以“出现”和“消失”以及系统嘟嘟声(也可以用对象表示),它可以只是嘟嘟声。那些是那些对象拥有的插槽。我们会称它们为“messageAppear”,“messageDisappear”和“beep”。

假设您希望每当复选框被切换时系统会发出嘟嘟声,并且标签出现或消失,具体取决于用户是选中还是清除了复选框。

您将以下信号从而连接到下面的插槽(信号左侧,右侧插槽):

checkboxToggled -> beep 
checkboxSet -> messageAppear 
checkboxUnset -> messageDisappear 

这基本上它。

信号和插槽也可能有参数。例如,使用设置数字值的滑块,只要用户移动滑块,您就希望将已更改的值与发出的信号一起发送:sliderChanged(int)。

当然,要真正做一些有用的事情,你会写一些自己的类,其中将包含一些自己的信号和插槽。这很容易完成,使用这些自己的信号和插槽,您可以以事件驱动的方式与GUI或代码的其他部分进行交互。

请记住,信号和时隙通常是对称的,因为通常可能存在对应于时隙的信号。例如,一个复选框可以在切换时发出信号,但也可能包含切换复选框本身的插槽。这将很容易实现分离总是相互对立的复选框。

0

有一个常见的误解,认为类是人,狗,自行车等名词。那么认为一个人(例如)有一只狗和一辆自行车是有意义的。

让我们从什么对象(应该是)开始吧。对象是数据和过程。什么是程序?数据和程序。对象应该是(相对)“小”的独立子程序。因为oo编程非常模糊和被滥用(需要引用),所以人们认为所有东西都需要成为一个阶级或一个对象。事实并非如此,对象是具有“小”API(公共子例程)的“小型”独立程序。有些程序员甚至不把他们的项目分解成子程序,只是使用数据和程序更合适的对象。现在,假设我们同意对象是程序,我们可能会同意,在大多数情况下,程序不需要拥有其他类似大小和复杂程序的副本(即一个对象不指向另一个指针对象),它可能需要较小的程序来管理数据(如数据结构),但imho不需要其他对象。

为什么?因为耦合对象使它们依赖。为什么那么糟糕?因为当对象是独立的时候,你可以测试它们,也可以向其他程序员和客户承诺该对象(一个小的独立程序)能够高度确定地执行某些任务。只要没有对该对象进行任何更改,您也可以确定它会继续执行。

那么什么是插槽和信号?如果你明白对象就像程序一样,并且它们不应该理想地持有副本或指向其他对象的指针,而不需要某种方式让它们进行通信。例如,在您的计算机上运行的进程可以使用套接字,IP地址和端口进行通信。对象可以使用与RPC非常相似的内容,称为信号和插槽。这些数据结构旨在作为存储对象子例程(slots)的两个较大对象的中间数据结构,并允许其他对象使用合适的参数调用(signal)这些子例程(slots),而无需了解除这些参数以外的任何其他对象要求。

所以底层结构是(可能)强类型过程指针的集合(可能是数组),其他对象可以用适当的参数调用,而不用指向这些对象的指针。调用者只需要访问信号对象(不包含实现细节)来定义预期的参数。

这也是灵活的,因为它允许一些特殊的用例,例如只响应一次信号的插槽,一个信号的多个插槽以及其他类似的用例如反弹。