2008-11-23 18 views
13

Czy ktoś może wyjaśnić w prosty sposób wzór "sygnałów i gniazd"?Co to są sygnały i gniazda?

+1

masz na myśli sygnały Qt i automaty? –

+0

Wzór ogólnie. Wikipedia wskazuje, że doładowanie też to robi. – JeffV

Odpowiedz

18

Sygnały i gniazda są sposobem oddzielenia nadawcy (sygnału) od zera lub większej liczby odbiorników (gniazda). Załóżmy, że masz system, który ma zdarzenia, które chcesz udostępnić dowolnej innej części systemu zainteresowanej tymi wydarzeniami. Zamiast twardego okablowania kodu, który generuje zdarzenie do kodu, który chce wiedzieć o tych zdarzeniach, używałbyś wzorca sygnałów i gniazd.

Gdy nadawca sygnalizuje zdarzenie (zwykle przez wywołanie funkcji powiązanej z tym zdarzeniem/sygnałem), wszystkie odbiorniki tego zdarzenia są automatycznie wywoływane. Pozwala to na podłączanie i odłączanie odbiorników w razie potrzeby w trakcie trwania programu.

Ponieważ to pytanie zostało oznaczone jako C++, tutaj znajduje się link do biblioteki Boost.Signals, która zawiera dużo dokładniejsze wyjaśnienie.

4

Zakładam, że mówisz o sygnałach i gniazdach QT.
To bardzo proste.

Wystąpienie klasy może wystrzelić sygnał, a inna instancja prawdopodobnie innej klasy może złapać ten sygnał w gnieździe. To trochę jak wywołanie funkcji, że facet, który wywołuje tę funkcję, nie musi wiedzieć, kto chce odebrać połączenie.

Najlepszym sposobem zilustrowania jest przykład.
Klasa QPushButton ma sygnał QPushButton :: clicked(). Ten sygnał jest uruchamiany po kliknięciu przycisku. Przycisk nie musi wiedzieć, kto jest zainteresowany, że nastąpiło kliknięcie. po prostu odpala sygnał i ktokolwiek zainteresowany może się z nim połączyć.
QDialog, w którym umieszczony jest przycisk, jest zainteresowany, aby wiedzieć, kiedy przycisk został kliknięty. Ma slot MyDialog :: buttonClicked(). W MyDialog c'tor musisz podłączyć() przyciski click() do przycisku dialogowego ButtonClicked(), tak aby slot był wywoływany, gdy sygnał jest uruchamiany.

A kilka bardziej zaawansowanych rzeczy:

  • Argumenty, sygnał może mieć argumenty i te argumenty mogą ewentualnie być przekazywane do gniazda, jak również.
  • połączenia z wątkami krzyżowymi - jeśli tworzysz połączenie sygnału, które musi być przekierowane, QT automatycznie buforuje sygnały i umieszcza je w odpowiednim wątku. Dzieje się to automatycznie, na przykład, gdy wątek GUI musi się komunikować z działającym wątkiem.

Here's more information in QT's documentation.

12

myślę można opisać mechanizm sygnałów i slotów najlepiej, gdy patrzysz na nich jako ewentualnego pojazdu realizacji dla Observer Pattern or Publish/Subscriber Pattern. Jest jeden signal, na przykład buttonPressed(IdType) po stronie wydawcy. Po każdym naciśnięciu przycisku wywoływane są wszystkie gniazda, które są podłączone do tego sygnału. Sloty znajdują się po stronie subskrybenta. Slot może na przykład być sendMail(IdType).

Wraz z "naciśnięciem przycisku" zdarzenia, gniazdo będzie wiedzieć, który przycisk został naciśnięty, ponieważ identyfikator zostałby przekazany. IdType reprezentuje typ danych przesyłanych przez połączenie między Wydawcą a subskrybentem. Operacja możliwa dla subskrybenta to connect(signal, slot), która może połączyć buttonPressed(IdType) z sendMail(IdType), tak że po naciśnięciu przycisku, ten konkretny slot jest wywoływany.

Dobrą rzeczą jest to, że subskrybent (strona boków) nie musi dbać o szczegóły sygnału. To po prostu musi się połączyć. Tak więc tutaj mamy dużą liczbę luźnych połączeń . Możesz zmienić implementację przycisków, ale interfejs dla slotów nadal będzie taki sam.

Aby uzyskać więcej informacji, patrz: Qt Signals/Slots lub Boost Signals.

6

Wyobraź sobie, że masz GUI w swojej aplikacji. Przez większość czasu przepływ sterowania nie byłby bardzo liniowy, tj. Zamiast mieć przejrzystą sekwencję czynności, użytkownik miałby interakcję z GUI (podobnie jak przyciski, menu itp.).

Jest to w istocie model sterowany zdarzeniami, który może być zaimplementowany całkiem przyjemnie ze wzorem sygnałów i szczelin. sygnały są zdarzeniami, które są generowane przez obiekty (myślę, komponenty GUI), a gniazda są odbiorcami tych zdarzeń.

Oto przykład: wyobraź sobie, że masz pole wyboru, reprezentowane jako obiekt w twoim języku programowania. Wiele rzeczy może się zdarzyć z tym polem wyboru: można go przełączać, co z kolei oznacza również, że jest on ustawiony lub wyłączony. To są sygnały, które może on emitować. Nazwijmy je checkboxemToggled, checkboxSet i checkboxUnset. Jak widzisz, w tym przykładzie pole wyboru zawsze wyemituje checkboxToggled sygnał podczas przełączania, ale także dokładnie jeden z dwóch innych sygnałów, w zależności od tego, jak zmienia się stan.

Teraz wyobraź sobie, że masz jakieś inne obiekty, mianowicie etykietę, która dla tego przykładu zawsze istnieje jako obiekt, ale może "pojawić się" i "zniknąć" oraz sygnał dźwiękowy (również reprezentowany przez obiekt), który może po prostu sygnał dźwiękowy. To są automaty, które mają te obiekty. Nazwiemy je "messageAppear", "messageDisappear" i "beep".

Załóżmy, że chcesz, aby system generował sygnał dźwiękowy za każdym razem, gdy pole wyboru jest przełączane, a etykieta ma pojawiać się lub znikać w zależności od tego, czy użytkownik zaznaczył lub wyczyścił pole wyboru.

Można by zatem połączyć następujące sygnały do ​​następujących gniazd (sygnały z lewej strony, z prawej strony gniazda):

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

To właściwie wszystko.

Sygnały i gniazda mogą również zawierać argumenty. Na przykład, używając suwaka, który ustawia wartość liczbową, chciałbyś wysłać zmienioną wartość wraz z wysyłanym sygnałem, gdy tylko użytkownik przesunął suwak: sliderChanged (int).

Oczywiście, aby rzeczywiście zrobić coś pożytecznego, napisałbyś kilka własnych klas, które zawierałyby własne sygnały i gniazda. Odbywa się to dość łatwo i przy użyciu tych własnych sygnałów i gniazd, masz dobry sposób na interakcję z GUI lub innymi częściami kodu w sposób sterowany wydarzeniami.

Należy pamiętać, że sygnały i gniazda są często symetryczne w tym sensie, że często może występować sygnał odpowiadający szczelinie. Na przykład, pole wyboru może emitować sygnał podczas przełączania, ale może również zawierać gniazdo, które przełącza samo pole wyboru. Łatwo byłoby wdrożyć oddzielne pola wyboru, które zawsze są ustawione przeciwnie do siebie.

1

Najlepszy przykład i wyjaśnienie, które znalazłem dla sygnałów i gniazd, to this code project article.

+2

Należy zauważyć, że [odpowiedzi dotyczące tylko łącza] (http://meta.stackoverflow.com/tags/link-only-answers/info) są odradzane, odpowiedzi SO powinny być punktem końcowym wyszukiwania rozwiązania (vs. jeszcze jeden przystanek referencji, które z czasem zanikają). Proszę rozważyć dodanie samodzielnego streszczenia tutaj, zachowując odnośnik jako odniesienie. – kleopatra

+0

Myślę, że dobrze jest mieć linki. – VivekDev

0

Istnieje powszechne nieporozumienie, że klasy są rzeczownikami takimi jak Osoba, Pies, Rower i tym podobne. W takim razie warto pomyśleć, że osoba (instancja) ma psa i rower.

Zacznijmy od tego, jakie obiekty są (powinny być). Obiekty to dane i procedury. Czym są programy? Dane i procedury. Obiekty mają być (stosunkowo) "małymi" niezależnymi podprogramami. Ponieważ programowanie O jest nauczane bardzo niejasno i niewłaściwie (potrzeba cytowania), ludzie myślą, że wszystko musi być klasą lub obiektem. Tak nie jest, obiekty są "małymi" niezależnymi programami z "małym" API (publiczne podprogramy). Niektórzy programiści nawet nie dzielą projektu na podprogramy i po prostu używają obiektów, w których dane i procedury są bardziej odpowiednie.

Teraz, zakładając, że zgadzamy się, że obiekty są programami, możemy zgodzić się, że w większości przypadków programy nie muszą mieć kopii innych programów o podobnej wielkości i złożoności (np. Obiekt nie jest wskaźnikiem do innego obiekt), może potrzebować mniejszych programów do zarządzania danymi (takich jak struktury danych), ale imho nie potrzebuje innego obiektu.

Dlaczego? Ponieważ sprzężenie obiektów powoduje ich zależność. Dlaczego to jest złe? Ponieważ obiekty są niezależne, można je przetestować, a także obiecać innym programistom i klientom, że obiekt (mały niezależny program) jest w stanie wykonywać pewne zadania z dużą pewnością. Możesz także być pewien, że będzie działał tak długo, dopóki nie zostaną wprowadzone żadne zmiany w tym obiekcie.

Co to są gniazda i sygnały? Jeśli rozumiesz, że obiekty są jak programy i nie powinny idealnie trzymać kopii lub wskaźników do innych obiektów, niż potrzebujesz do ich komunikacji. Na przykład procesy uruchomione na komputerze mogą wykorzystywać gniazda, adresy IP i porty do komunikacji. Obiekty mogą używać czegoś bardzo podobnego do sygnałów o nazwie i gniazdach. Są to struktury danych przeznaczone do pośredniczenia między dwoma większymi obiektami przechowującymi podprogramy obiektu (slots) i zezwalają innym obiektom na wywoływanie (signal) tych podpunktów (slots) z odpowiednimi parametrami, nie wiedząc nic o tych innych obiektach, poza tymi, których parametry wymagać.

Tak więc podstawową strukturą są zestawy (prawdopodobnie tablice) (prawdopodobnie) ściśle określonych wskaźników procedur, które inne obiekty mogą wywoływać z odpowiednimi parametrami bez wskaźnika do tych obiektów. Wywoływacze potrzebują jedynie dostępu do obiektu sygnału (który nie zawiera szczegółów implementacji), który definiuje oczekiwane parametry.

Jest także elastyczny, ponieważ umożliwia korzystanie z niektórych specjalnych przypadków, takich jak gniazda, które reagują tylko na sygnał jeden raz, wiele gniazd dla jednego sygnału i inne podobne przypadki użycia, takie jak rozwijanie.