12

使用 Reactive Extensions,我可以想出多种方法来对具有副作用 / IO 的操作进行建模——比如订阅来自聊天室的消息。我可以接受参数(比如聊天室)和一个观察者,返回一个 Disposable,即

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

或者在给定参数的情况下返回一个 Observable,即

Observable<ChatMessage> GetObservableFor(string chatRoom)

当返回一个 Observable 时,我还可以选择让它“热”或“冷”,即在调用我的方法或订阅 observable 时执行实际订阅。此外,我可以使 observable 复用或不复用,即当 Observable 有多个订阅者时共享相同的底层订阅,或者每次订阅时发起一个新请求。

对于订阅带有参数的外部事件源的操作,是否有最佳实践方法?

4

3 回答 3

7

返回 * I *Observable 会好得多,因为您可以将返回的 IObservable 与其他运算符组合在一起。尝试将事物放入自定义的 SubscribeTo 方法对我来说似乎是个坏主意,因为 SubscribeTo 没有任何可组合的东西,所以你有点把自己画到一个角落里。如果您返回 IObservable,那么您可以稍后决定是否要发布/延迟等...,只要您愿意,只需使用现有的 IO 运算符即可。如果你在SubscribeTo 中这样做,那就是决定了,一切都必须承担后果。该行为将包含在 SubscribeTo 中,这违背了 IO 的目的……明确说明任何副作用。

于 2013-08-19T14:48:52.873 回答
3

我同意其他两个答案。我想进一步补充一些说明:

  1. 如果你的 observable 序列是 Hot,它几乎肯定是共享的。因此,当您将 Hot 和 Shared 视为不同的事物时,听起来您可能会有些困惑。
  2. 我认为订阅有副作用是可以的。在函数式编程中,大多数关于避免副作用的讨论都是关于管道中的运算符,而不是管道的构造。Where即不要在您的/ Select/ Takeetc... 运算符中产生副作用。这样做会产生不和谐的体验并导致不可预测的结果。这妨碍了作为 FP 基石的安全构图。
  3. 将参数传递给返回可观察序列的方法是完全可以的!您的样本是何时这样做的一个很好的例子。其他示例包括订阅频道、端点、会话、计时器等...
  4. 避免使用IObservable<T>. 这只是一个禁忌。我已经使用 Rx 超过 3 年了,完全不需要它。即使使用 Subject 实现也很少发生。正如 Brad 所说,使用Observable.Create来创建序列。*

总而言之,我建议您最终得到一个如下所示的界面:

IObservable<ChatMessage> MessagesFor(string chatRoom)

关于共享可观察序列的问题,您需要根据自己的要求和架构来决定。有时您可能会发现底层传输层会为您执行此操作,因此您无需编写代码。有时您可能会发现共享订阅意味着第二个以上的订阅者可能会错过仅在订阅时出现的消息(例如世界状态)。您可以通过使用 ReplaySubject 作为您的 MultiCaster 来克服这个问题。这引发了其他问题;您准备好承担存储 ChatMessages 的无限成本了吗?

*披露:链接是我自己的网站

于 2013-08-29T09:21:04.113 回答
3

IObservable有一个名为 Subscribe 的方法,其中包含大量重载。您没有理由编写自定义的 SubscribeTo 方法。这是一种反模式。

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

使多播在第一个订阅时变热,然后在删除最后一个订阅时变冷。

于 2013-08-19T20:16:04.730 回答