2012-12-18 9 views
15

Projektuję pakiet, w którym chcę zapewnić interfejs API w oparciu o wzorzec obserwatora: oznacza to, że istnieją punkty, w których chciałbym emitować sygnał, który wyzwoli zero lub więcej zainteresowanych stron. Te zainteresowane strony niekoniecznie muszą wiedzieć o sobie nawzajem.Czy istnieje preferowany sposób projektowania interfejsów API sygnałów lub zdarzeń w programie Go?

Wiem, że mogę zaimplementować taki interfejs API od podstaw (np. Przy użyciu kolekcji kanałów lub funkcji wywołania zwrotnego), ale zastanawiałem się, czy istnieje preferowany sposób tworzenia takich interfejsów API.

W wielu językach i frameworkach, z którymi grałem, istnieją standardowe sposoby tworzenia interfejsów API, które zachowują się tak, jak tego oczekują użytkownicy: np. funkcje g_signal_* dla aplikacji opartych na glib, zdarzeń i addEventListener() dla aplikacji DOM JavaScript lub delegatów multiemisji dla .NET.

Czy jest coś podobnego do Go? Jeśli nie, to czy istnieje inny sposób struktury tego typu API, który jest bardziej idiomatyczny w Go?

Odpowiedz

15

Powiedziałbym, że goroutin odbierający z kanału jest do pewnego stopnia analogiem obserwatora. Idiomatycznym sposobem na ujawnienie zdarzeń w Go byłoby zatem, aby IMHO zwrócił kanały z pakietu (funkcji). Inną obserwacją jest to, że wywołania zwrotne nie są używane zbyt często w programach Go. Jednym z powodów jest również istnienie potężnego select statement.

Ostatnia uwaga: niektórzy (ja też) uważają, że wzory GoF to Go antipatterns.

+2

myślę, że to odpowiedź obejmuje kilka przypadków użycia, ale na pewno bym chciał usłyszeć więcej opinii/odpowiedzi na ten temat. Kanały nakładają na dzwoniącego trochę więcej ("obserwatora"), ponieważ musi on uruchomić goroutine, które czeka na tym kanale. Jeśli ta sama funkcja może obsłużyć wiele "zdarzeń", może to być uciążliwe. Jako przeciw-przykład, callbacks są używane w sieci/http dla procedur obsługi HTTP. Istnieją przypadki użycia, w których bardziej sensowne są IMHO. – mna

+0

Użyłem tylko terminu "wzorzec obserwatora", ponieważ jest to termin, który ludzie mogą zrozumieć: nie piszę swoich programów, najpierw rozbijając je na nazwane wzorce projektowe, jeśli to właśnie robisz. Jeśli chodzi o sugestie dotyczące interfejsu API, widzę, jak funkcja zwracająca kanały po stronie czytelnej może działać po stronie subskrypcji, ale w jaki sposób modelowałbyś pasujący interfejs API wypisać? –

+5

Kanały są porównywalne pod względem równości i są obiektami pierwszej klasy. Aby zrezygnować z subskrypcji, wystarczy przekazać kanał z powrotem do przeglądarki, może on znaleźć swój kanał i podjąć odpowiednie działania w celu zakończenia subskrypcji. – Sonia

4

Go oferuje wiele narzędzi do projektowania api sygnału.

Najpierw trzeba zdecydować się kilka rzeczy:

Chcesz push lub model przyciągania? na przykład. Czy wydawca przesyła zdarzenia do subskrybentów lub czy subskrybenci pobierają wydarzenie od wydawcy?

Jeśli chcesz system wypychania, to posiadanie subskrybentów, dających wydawcy kanał do wysyłania wiadomości, będzie działać naprawdę dobrze. Jeśli chcesz użyć metody ściągania, działa tylko okno komunikatu chronione muteksem. Poza tym, nie wiedząc więcej o twoich wymaganiach, trudno podać więcej szczegółów.

+0

W moim konkretnym przypadku, to wydawca emituje wydarzenia i subskrybentów, reagując tak szybko, jak to możliwe. Jest to przypadek, w którym interaktywność byłaby ważniejsza niż przepustowość, jeśli o to prosisz. –

1

Powiedziałbym, że nie ma standardowego sposobu robienia tego, ponieważ kanały są wbudowane w język. Nie ma biblioteki kanałów ze standardowymi sposobami robienia rzeczy z kanałami, są po prostu kanały. Posiadanie kanałów zbudowanych w obiektach pierwszej klasy uwalnia od konieczności posługiwania się standardowymi technikami i pozwala rozwiązywać problemy w najprostszy, najbardziej naturalny sposób.

+0

Wiem o kanałach (nawet wspomniałem o nich w pytaniu). Ale kanały naprawdę oferują tylko mechanizm komunikacji 1-1, a ja chcę 1-wiele (gdzie wiele może być zero). Tak naprawdę nie mogę tworzyć kanałów API i nic więcej. –

+1

Nieprawda w ogóle. Kanały mogą mieć wielu nadawców i wiele odbiorników. W każdym razie równie dobrze możesz narzekać, że zmienne nie są dobre, ponieważ mogą zawierać tylko jedną wartość naraz. Potrzeba więcej? Użyj struktury danych. Wydawca może przechowywać wszystkich swoich subskrybentów w plasterku, mapie, strukturze drzewa, co ma sens w Twojej sprawie. Aby opublikować, wykonaj iterację struktury danych i wyślij aktualizację do każdego subskrybenta. – Sonia

+0

Odnosiłem się do kanałów jako 1-1 w tym sensie, że dla każdej wiadomości kanał łączy jednego nadawcę z jednym odbiornikiem. Chociaż z pewnością można użyć wielu odbiorników np. dzielcie pracę między goroutinami, co oczywiście nie jest tym, o co pytałem. –

3

Potrzebowałem czegoś typu "wzorca obserwatora" w kilku projektach. Here's a reusable example z ostatniego projektu.

Ma odpowiedni test, który pokazuje, jak z niego korzystać.

Podstawowa teoria mówi, że emulator zdarzeń wywołuje Submit z pewną ilością danych, gdy pojawi się coś ciekawego. Każdy klient, który chce być świadomy tego zdarzenia, będzie kanałem, z którego odczytuje dane o zdarzeniach. Ten zarejestrowany kanał może być użyty w pętli select lub możesz go odczytać bezpośrednio (lub buforować i odpytywać).

Gdy skończysz, jesteś Unregister.

Nie jest to idealne rozwiązanie dla przypadków wszystkich (np.Mogę chcieć, aby zwolennicy siły wyrejestrowywali coś dla powolnych obserwatorów), ale działa tam, gdzie go używam.

Powiązane problemy