使用Reactive Extensions,我可以想到许多方法来模拟具有副作用/ IO的操作 - 比如订阅来自聊天室的消息。我可以接受参数(比如聊天室)和观察者,返回一个Disposable,即
Disposable SubscribeTo(string chatRoom, Observer<ChatMessage> observer)
给出参数,或返回一个Observable,即
Observable<ChatMessage> GetObservableFor(string chatRoom)
当返回一个Observable时,我还可以选择使其成为“热”还是“冷”,即在调用我的方法或订阅observable时执行实际订阅。另外,我可以使可观察的多路复用与否,即当Observable有多个用户时共享相同的基础订阅,或者每次订阅时发起新的请求。
对于订阅带参数的外部事件源的操作,是否有使用RX的最佳实践方法?
回归*一世* Observable要好得多,因为您可以与其他运算符组合返回的IObservable。尝试将东西放入自定义的SubscribeTo方法对我来说似乎是一个坏主意,因为没有关于SubscribeTo的任何组合,所以你有点把自己画成一个角落。如果您返回IObservable,那么您可以稍后决定是否要发布/推迟等等...,只需使用现有的IO运算符即可。如果你在SubscribeTo中做到了,那就决定了,所有事情都必须分担后果。这种行为将被包含在SubscribeTo中,这违背了IO的目的......明确任何副作用。
回归*一世* Observable要好得多,因为您可以与其他运算符组合返回的IObservable。尝试将东西放入自定义的SubscribeTo方法对我来说似乎是一个坏主意,因为没有关于SubscribeTo的任何组合,所以你有点把自己画成一个角落。如果您返回IObservable,那么您可以稍后决定是否要发布/推迟等等...,只需使用现有的IO运算符即可。如果你在SubscribeTo中做到了,那就决定了,所有事情都必须分担后果。这种行为将被包含在SubscribeTo中,这违背了IO的目的......明确任何副作用。
IObservable
有一个名为Subscribe的方法,有大量的重载。您没有理由编写自定义的SubscribeTo方法。这是一种反模式。
var o = ChatRoom.ObservableFor("alt.buddha.short.fat.guy").Publish().RefCount()
使第一个订阅热门的多播然后在最后一个订阅被删除时冷。
我同意其他两个答案。我想进一步补充一些说明:
- 如果您的可观察序列是Hot,则几乎可以肯定它是共享的。因此,当你谈论Hot和Shared作为不同的东西时,听起来你可能会有些困惑。
- 我觉得这很好 订阅 有副作用。在功能编程中,关于避免副作用的大多数讨论都是关于 运营商 在管道中,而不是管道的建设。即不要在你的身上产生副作用
Where
/Select
/Take
等......运营商。这样做会产生刺耳的体验并导致不可预测的结果。这可以防止安全的成分,这是FP的基石。
- 将参数传递给返回可观察序列的方法是完全没问题的!您的样本是何时这样做的一个很好的例子。其他示例包括订阅频道,端点,会话,计时器等...
- 避免使用自定义实现
IObservable<T>
。这只是禁忌。我已经使用Rx超过3年了,而且没有必要。即使使用Subject实现也很少见。正如布拉德所说,期待 Observable.Create 用于创建序列。*
总而言之,我建议你最终得到一个如下所示的界面:
IObservable<ChatMessage> MessagesFor(string chatRoom)
关于共享可观察序列的问题,您需要根据自己的要求和架构来决定。有时您可能会发现底层传输层将为您执行此操作,因此您无需对其进行编码。其他时候您可能会发现共享订阅意味着第二个+订阅者可能会错过仅在订阅时发生的消息(例如,State-Of-World)。你可以通过使用ReplaySubject作为你的MultiCaster来实现这个目标。这提出了其他问题;你准备好承担存储ChatMessages的可能无限制的费用吗?
*披露:链接到我自己的网站