Udostępnij przez


Najlepsze rozwiązania dotyczące wzorca projektowego obserwatora

Na platformie .NET wzorzec projektowy obserwatora jest implementowany jako zestaw interfejsów. Interfejs System.IObservable<T> reprezentuje dostawcę danych, który jest również odpowiedzialny za zapewnienie IDisposable implementacji, która umożliwia obserwatorom anulowanie subskrypcji powiadomień. Interfejs System.IObserver<T> reprezentuje obserwatora. W tym temacie opisano najlepsze rozwiązania, które deweloperzy powinni przestrzegać podczas implementowania wzorca projektowego obserwatora przy użyciu tych interfejsów.

Wątkowanie

Zazwyczaj dostawca implementuje IObservable<T>.Subscribe metodę przez dodanie określonego obserwatora do listy subskrybentów reprezentowanej przez jakiś obiekt kolekcji i implementuje IDisposable.Dispose metodę przez usunięcie określonego obserwatora z listy subskrybentów. Obserwator może wywołać te metody w dowolnym momencie. Ponadto, ponieważ umowa dostawcy/obserwatora nie określa, kto jest odpowiedzialny za anulowanie subskrypcji po IObserver<T>.OnCompleted metodzie wywołania zwrotnego, dostawca i obserwator mogą próbować usunąć tego samego członka z listy. Z tego powodu metody Subscribe i Dispose powinny być bezpieczne wątkowo. Zazwyczaj wiąże się to z użyciem kolekcji współbieżnej lub blokady. Implementacje, które nie są bezpieczne wątkowo, powinny jawnie zaznaczyć, że nie są.

Wszelkie dodatkowe gwarancje należy określić w warstwie powyżej kontraktu dostawcy/obserwatora. Osoby wdrażające powinny wyraźnie zwracać uwagę, gdy nakładają dodatkowe wymagania, aby uniknąć nieporozumień użytkownika dotyczących umowy obserwatora.

Obsługa wyjątków

Ze względu na luźne sprzężenie między dostawcą danych a obserwatorem wyjątki we wzorcu projektowania obserwatora mają być informacyjne. Ma to wpływ na sposób, w jaki dostawcy i obserwatorzy obsługują wyjątki we wzorcu projektowania obserwatora.

Dostawca — wywoływanie metody OnError

Metoda OnError jest przeznaczona jako komunikat informacyjny dla obserwatorów, podobnie jak IObserver<T>.OnNext metoda. Jednak metoda została zaprojektowana tak, OnNext aby zapewnić obserwatorowi bieżące lub zaktualizowane dane, natomiast OnError metoda została zaprojektowana tak, aby wskazać, że dostawca nie może dostarczyć prawidłowych danych.

Dostawca powinien postępować zgodnie z tymi najlepszymi rozwiązaniami podczas obsługi wyjątków i wywoływania OnError metody:

  • Dostawca musi obsługiwać własne wyjątki, jeśli ma określone wymagania.

  • Dostawca nie powinien oczekiwać lub wymagać, aby obserwatorzy obsługiwali wyjątki w żaden konkretny sposób.

  • Dostawca powinien wywołać metodę OnError , gdy obsługuje wyjątek, który narusza jego zdolność do dostarczania aktualizacji. Informacje na temat takich wyjątków można przekazać do obserwatora. W innych przypadkach nie ma potrzeby powiadamiania obserwatorów o wyjątku.

Gdy dostawca wywoła metodę OnError lub IObserver<T>.OnCompleted, nie powinno być dalszych powiadomień, a dostawca może anulować subskrypcję swoich obserwatorów. Obserwatorzy mogą jednak w dowolnym momencie anulować subskrypcję, w tym zarówno przed, jak i po otrzymaniu powiadomieniaOnError.IObserver<T>.OnCompleted Wzorzec projektowy obserwatora nie określa, czy dostawca albo obserwator jest odpowiedzialny za anulowanie subskrypcji; w związku z tym istnieje możliwość, że oba podmioty mogą próbować anulować subskrypcję. Zazwyczaj, gdy obserwatorzy rezygnują z subskrypcji, są usuwani z kolekcji subskrybentów. W aplikacji jednowątkowej implementacja IDisposable.Dispose powinna upewnić się, że odwołanie do obiektu jest prawidłowe i że obiekt jest członkiem kolekcji subskrybentów przed podjęciem próby jego usunięcia. W aplikacji wielowątkowej należy użyć kolekcji bezpiecznej dla wątków, takiej jak System.Collections.Concurrent.BlockingCollection<T>.

Obserwator — implementowanie metody OnError

Gdy obserwator otrzymuje powiadomienie o błędzie od dostawcy, obserwator powinien traktować wyjątek jako informacyjny i nie powinien być wymagany do podjęcia żadnej konkretnej akcji.

Obserwator powinien postępować zgodnie z tymi najlepszymi rozwiązaniami podczas odpowiadania na OnError wywołanie metody od dostawcy:

  • Obserwator nie powinien zgłaszać wyjątków od implementacji interfejsu, takich jak OnNext lub OnError. Jeśli jednak obserwator zgłasza wyjątki, powinien oczekiwać, że te wyjątki nie będą obsługiwane.

  • Aby zachować stos wywołań, obserwator, który chce zgłosić obiekt przekazany do jego Exception metody, powinien owinąć OnError wyjątek przed jego zgłoszeniem. W tym celu należy użyć standardowego obiektu wyjątku.

Dodatkowe najlepsze rozwiązania

Próba wyrejestrowania w metodzie IObservable<T>.Subscribe może skutkować odwołaniem do obiektu o wartości null. W związku z tym zalecamy unikanie tej praktyki.

Chociaż istnieje możliwość dołączenia obserwatora do wielu dostawców, zalecanym wzorcem jest dołączenie wystąpienia IObserver<T> tylko do jednego wystąpienia IObservable<T>.

Zobacz także