Поделиться через


Рекомендации по проектированию шаблонов наблюдателя

В .NET шаблон конструктора наблюдателя реализуется как набор интерфейсов. Интерфейс System.IObservable<T> представляет поставщика данных, который также отвечает за предоставление IDisposable реализации, позволяющей наблюдателям отписываться от уведомлений. Интерфейс System.IObserver<T> представляет наблюдателя. В этом разделе описаны рекомендации, которые разработчики должны следовать при реализации шаблона проектирования наблюдателя с помощью этих интерфейсов.

Нарезание резьбы

Как правило, поставщик реализует IObservable<T>.Subscribe метод путем добавления определенного наблюдателя в список подписчиков, представленный некоторым объектом коллекции, и он реализует IDisposable.Dispose метод, удаляя конкретного наблюдателя из списка подписчиков. Наблюдатель может вызывать эти методы в любое время. Кроме того, поскольку контракт поставщика или наблюдателя не указывает, кто несет ответственность за отмену подписки после метода обратного IObserver<T>.OnCompleted вызова, поставщик и наблюдатель могут попытаться удалить одного и того же члена из списка. Из-за этой возможности методы Subscribe и Dispose должны быть потокобезопасными. Как правило, это предполагает использование параллельной коллекции или блокировки. Реализации, которые не являются потокобезопасными, должны явно указывать это в документации.

Все дополнительные гарантии должны быть указаны в слое поверх контракта поставщика или наблюдателя. Исполнители должны четко указывать, когда они накладывают дополнительные требования, чтобы избежать путаницы пользователей в отношении контракта условий наблюдения.

Обработка исключений

В связи со слабой связью между поставщиком данных и наблюдателем, исключения в шаблоне проектирования наблюдателя носят информационный характер. Это влияет на то, как поставщики и наблюдатели обрабатывают исключения в шаблоне проектирования наблюдателя.

Поставщик— вызов метода OnError

Этот OnError метод предназначен как информационное сообщение наблюдателям, так же как и метод IObserver<T>.OnNext. OnNext Однако метод предназначен для предоставления наблюдателя текущих или обновленных данных, а OnError метод предназначен для указания того, что поставщик не может предоставить допустимые данные.

Поставщик должен следовать этим рекомендациям при обработке исключений и вызове OnError метода:

  • Поставщик должен обрабатывать собственные исключения, если он имеет определенные требования.

  • Поставщик не должен ожидать или требовать, чтобы наблюдатели обрабатывали исключения определенным образом.

  • Поставщик должен вызвать OnError метод, когда он обрабатывает исключение, которое компрометирует возможность предоставления обновлений. Сведения о таких исключениях можно передать наблюдателю. В других случаях нет необходимости уведомлять наблюдателей об исключении.

После того как поставщик вызовет метод OnError или IObserver<T>.OnCompleted, не должно быть дальнейших уведомлений, и поставщик может отменить подписку своих наблюдателей. Однако наблюдатели также могут отменить подписку в любое время, включая как до, так и после получения OnError или IObserver<T>.OnCompleted уведомления. Шаблон проектирования наблюдателя не определяет, отвечает ли поставщик или наблюдатель за отмену подписки; Таким образом, существует вероятность того, что оба могут попытаться отменить подписку. Как правило, при отмене подписки наблюдатели удаляются из коллекции подписчиков. В однопоточном приложении данная реализация должна убедиться в том, что ссылка на объект действительна и что объект является членом коллекции подписчиков, прежде чем пытаться удалить его. В многопоточных приложениях следует использовать объект коллекции, безопасный для потоков, например объект System.Collections.Concurrent.BlockingCollection<T>.

Наблюдатель — реализация метода OnError

Когда наблюдатель получает уведомление об ошибке от поставщика, наблюдатель должен рассматривать исключение как информационное и не должен принимать каких-либо конкретных действий.

Наблюдатель должен следовать этим рекомендациям при реагировании на OnError вызов метода от поставщика:

  • Наблюдатель не должен выбрасывать исключения из своих реализаций интерфейса, таких как OnNext или OnError. Тем не менее, если наблюдатель создает исключения, он должен ожидать, что эти исключения будут необработанными.

  • Чтобы сохранить стек вызовов, наблюдатель, который хочет вызвать объект, переданный Exception методу OnError , должен упаковать исключение перед его вызовом. Для этой цели следует использовать стандартный объект исключения.

Дополнительные рекомендации

Попытка отменить регистрацию в методе IObservable<T>.Subscribe может привести к пустой ссылке. Поэтому рекомендуется избежать этой практики.

Хотя наблюдатель можно подключить к нескольким поставщикам, рекомендуется подключить IObserver<T> экземпляр только к одному IObservable<T> экземпляру.

См. также