2008-11-23 71 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),而無需瞭解除這些參數以外的任何其他對象要求。

所以底層結構是(可能)強類型過程指針的集合(可能是數組),其他對象可以用適當的參數調用,而不用指向這些對象的指針。調用者只需要訪問信號對象(不包含實現細節)來定義預期的參數。

這也是靈活的,因爲它允許一些特殊的用例,例如只響應一次信號的插槽,一個信號的多個插槽以及其他類似的用例如反彈。