Лучшая практика с использованием RX - вернуть Наблюдаемый или принять Наблюдателя?

Используя Reactive Extensions, я могу придумать несколько способов моделирования операции с побочными эффектами /IO - скажем, подписаться на сообщения из чата. Я мог бы либо принимать параметры (например, чат-комнату), так и Наблюдатель, возвращая одноразовый, т.е.

Disposable SubscribeTo(string chatRoom, Observer<ChatMessage> observer)

или вернуть наблюдаемый параметр, т.е.

Observable<ChatMessage> GetObservableFor(string chatRoom)

При возврате Observable у меня есть выбор между тем, чтобы сделать его "горячим" или "холодным", т.е. выполнять фактическую подписку либо при вызове метода, либо при подписке на наблюдаемый. Кроме того, я мог бы сделать наблюдаемый мультиплексированный или нет, т.е. Использовать одну и ту же базовую подписку, когда есть несколько подписчиков Observable или инициировать новый запрос каждый раз, когда он подписан.

Существует ли передовой подход к этому с использованием RX для операций, которые подписываются на внешний источник событий с параметрами?

Ответ 1

Возвращение * я * Observable намного лучше, так как тогда вы можете составить возвращаемый IObservable с другими операторами. Попытка помещать вещи в настраиваемый метод SubscribeTo кажется мне плохой идеей, потому что в SubscribeTo нет ничего сложного, поэтому вы как бы рисуете себя в угол. Если вы вернете IObservable, вы можете позже решить, хотите ли вы публиковать/откладывать и т.д., Когда захотите, просто используя существующие операторы для ввода-вывода. Если вы сделаете это внутри SubscribeTo, он решил, и все должно принять участие в последствиях. Поведение будет завершено в SubscribeTo, что приведет к поражению цели IO... чтобы быть явным о любых побочных эффектах.

Ответ 2

IObservable имеет метод под названием "Подписка" с тонной перегрузкой. Нет причин для написания настраиваемого метода SubscribeTo. Это анти-шаблон.

var o = ChatRoom.ObservableFor("alt.buddha.short.fat.guy").Publish().RefCount()

чтобы сделать многоадресную рассылку, горячую по первой подписке, затем холодную, когда последняя подписка будет удалена.

Ответ 3

Я согласен с двумя другими ответами. Я хотел бы дополнительно добавить некоторые пояснения:

  • Если ваша наблюдаемая последовательность "Горячая", ее почти наверняка разделяют. Таким образом, похоже, что у вас может быть некоторая путаница, когда вы говорите о Hot и Shared как о разных вещах.
  • Я думаю, это нормально для подписки, чтобы иметь побочные эффекты. В функциональном программировании большинство обсуждений об избежании побочных эффектов относятся к операторам в трубопроводе, а не к конструкции трубопровода. т.е. не создавать побочные эффекты в операторе Where/Select/Take и т.д. Для этого создается неприятный опыт и приводит к непредсказуемым результатам. Это предотвращает безопасную композицию, которая является краеугольным камнем FP.
  • Является полностью прекрасным передавать параметры методу, который возвращает наблюдаемую последовательность! Ваш пример - отличный пример того, когда это сделать. Другие примеры включают подписку на канал, конечную точку, сеанс, таймер и т.д.
  • Избегайте использования пользовательских реализаций IObservable<T>. Это просто нет-нет. Я использую Rx уже более 3 лет, и это просто не нужно. Даже использование реализаций Subject является редким явлением. Как сказал Брэд, посмотрите Observable.Create для создания последовательностей. *

Подводя итог, я предлагаю вам получить интерфейс, который выглядит так:

IObservable<ChatMessage> MessagesFor(string chatRoom)

Ответьте на вопрос о совместном использовании наблюдаемых последовательностей, это то, что вам необходимо решить на основе ваших собственных требований и архитектуры. Иногда вы можете обнаружить, что базовые транспортные слои сделают это для вас, поэтому вам не нужно его кодировать. В других случаях вы можете обнаружить, что совместное использование подписки означает, что второй + подписчик может пропустить сообщения, которые появляются только при подписке (например, State-Of-World). Вы можете это сделать, используя ReplaySubject в качестве вашего MultiCaster. Это вызывает другие проблемы; вы готовы взять, возможно, неограниченную стоимость хранения ChatMessages?

* Раскрытие информации: ссылка на мой собственный сайт