Doporučené postupy pro návrhový vzor Pozorovatel
V .NET se vzor návrhu pozorovatele implementuje jako sada rozhraní. Rozhraní System.IObservable<T> představuje poskytovatele dat, který je také zodpovědný za poskytování IDisposable implementace, která umožňuje pozorovatelům odhlásit odběr oznámení. Rozhraní System.IObserver<T> představuje pozorovatele. Toto téma popisuje osvědčené postupy, které by vývojáři měli dodržovat při implementaci vzoru návrhu pozorovatele pomocí těchto rozhraní.
Dělení na vlákna
Poskytovatel obvykle implementuje metodu IObservable<T>.Subscribe přidáním konkrétního pozorovatele do seznamu odběratelů, který je reprezentován určitým objektem kolekce, a implementuje metodu IDisposable.Dispose odebráním konkrétního pozorovatele ze seznamu odběratelů. Pozorovatel může tyto metody kdykoli volat. Vzhledem k tomu, že smlouva zprostředkovatele nebo pozorovatele neurčuje, kdo je zodpovědný za zrušení odběru IObserver<T>.OnCompleted po metodě zpětného volání, může se poskytovatel i pozorovatel pokusit odebrat stejného člena ze seznamu. Z tohoto důvodu by obě SubscribeDispose metody měly být bezpečné pro přístup z více vláken. Obvykle se to týká použití souběžné kolekce nebo zámku. Implementace, které nejsou bezpečné pro přístup z více vláken, by měly explicitně zdokumentovat, že nejsou.
Jakékoli další záruky musí být zadány ve vrstvě nad kontraktem poskytovatele nebo pozorovatele. Implementátoři by měli jasně volat, když zakládají další požadavky, aby se zabránilo nejasnostem uživatelů ohledně smlouvy pozorovatele.
Zpracování výjimek
Vzhledem k volnému spojení mezi poskytovatelem dat a pozorovatelem jsou výjimky v vzoru návrhu pozorovatele určené jako informativní. To má vliv na to, jak zprostředkovatelé a pozorovatelé zpracovávají výjimky v vzoru návrhu pozorovatele.
Zprostředkovatel – volání metody OnError
Metoda OnError je určena jako informační zpráva pozorovatelům, podobně jako metoda IObserver<T>.OnNext . Metoda OnNext je však navržena tak, aby poskytovala pozorovateli aktuální nebo aktualizovaná data, zatímco OnError metoda je navržená tak, aby indikuje, že poskytovatel nemůže poskytnout platná data.
Poskytovatel by měl při zpracování výjimek a volání OnError metody postupovat podle těchto osvědčených postupů:
Poskytovatel musí zpracovávat vlastní výjimky, pokud má nějaké specifické požadavky.
Poskytovatel by neměl očekávat ani vyžadovat, aby pozorovatelé zpracovávali výjimky jakýmkoli konkrétním způsobem.
Poskytovatel by měl metodu OnError volat, když zpracovává výjimku, která ohrožuje jeho schopnost poskytovat aktualizace. Informace o těchto výjimkách lze předat pozorovateli. V jiných případech není nutné informovat pozorovatele o výjimce.
Jakmile poskytovatel zavolá metodu nebo IObserver<T>.OnCompleted metoduOnError, neměla by existovat žádná další oznámení a poskytovatel může odhlásit své pozorovatele. Pozorovatelé se ale můžou kdykoliv odhlásit, a to i předtím, než obdrží OnError oznámení nebo IObserver<T>.OnCompleted oznámení. Vzor návrhu pozorovatele neurčuje, zda je poskytovatel nebo pozorovatel zodpovědný za zrušení odběru; proto existuje možnost, že se oba mohou pokusit o odhlášení odběru. Když se pozorovatelé obvykle odhlásí, odeberou se z kolekce odběratelů. V aplikaci s jedním vláknem by implementace IDisposable.Dispose měla zajistit, aby odkaz na objekt byl platný a že objekt je členem kolekce odběratelů před pokusem o jeho odebrání. V vícevláknové aplikaci by se měl použít objekt kolekce bezpečné pro System.Collections.Concurrent.BlockingCollection<T> přístup z více vláken, jako je například objekt.
Pozorovatel – implementace metody OnError
Když pozorovatel obdrží od poskytovatele oznámení o chybě, měl by s výjimkou zacházet jako s informačními zprávami a neměl by být nutný k provedení konkrétní akce.
Pozorovatel by měl při odpovídání na OnError volání metody od poskytovatele postupovat podle těchto osvědčených postupů:
Pozorovatel by neměl vyvolat výjimky ze svých implementací rozhraní, například OnNext nebo OnError. Pokud však pozorovatel vyvolá výjimky, měl by očekávat, že tyto výjimky budou neošetřené.
Chcete-li zachovat zásobník volání, pozorovatel, který chce vyvolat Exception objekt, který byl předán jeho OnError metodě, by měl zabalit výjimku před jeho vyvolání. Pro tento účel by se měl použít standardní objekt výjimky.
Další osvědčené postupy
Pokus o zrušení registrace v IObservable<T>.Subscribe metodě může vést k nulovému odkazu. Proto doporučujeme, abyste se této praxi vyhnuli.
I když je možné připojit pozorovatele k více poskytovatelům, doporučeným vzorem je připojit IObserver<T> instanci pouze k jedné IObservable<T> instanci.