3

我想编写一个库,它可以与 Web 服务器通信,并将其中的数据公开给世界其他地方。Web 服务器没有什么特别之处,它公开了几种 REST 方法,主要是 GET 和 POST。

由于我对 Reactive Extensions 比较陌生(但我已经喜欢它了),所以我寻求建议。我决定图书馆的接口将公开 IObservables。但我不知道如何准确地实现这一点。我想我有几个选择:

1)暴露IObservable<IEnumerable<T>>。有道理,REST 服务一次返回所有请求的数据。用户调用Subscribe(),只推送一个IEnumerable,调用OnDone。所以 Subscribe() 需要被调用多次。

2)暴露IObservable<T>。我猜在某些情况下可能是一个不错的选择。Subscribe() 只会被调用一次,为了获取其他数据,会有方法 Refresh() 或 NextPage() (...) 来获取更多数据到流中。(那么IObservable<T> GetResource...它可能是一个属性,IObservable<T> Resource { get; }

3)忘记Rx,通过事件以老式方式进行(IMO最糟糕的事情)

4)其他方式?

有这方面经验的人吗?我关心的是刷新(请求新数据)、分页、组合结果以及通常具有良好的可维护设计。

谢谢任何建议

4

2 回答 2

2

我建议使用以下界面:

public interface IRestService
{
    IObservable<T> GetResources<T>();
}

这种选择背后有很多原因。

公开IObservable<IEnumerable<T>>混合反应与交互(或可观察与可枚举),并会迫使您的查询调用.ToObservable(),或者更糟糕的是,.ToEnumerable()构建一个基本SelectMany查询。最好让您的查询和订阅代码保持整洁。

现在,您建议使用 anIObservable<T>您只需订阅一次,并且您需要使用RefreshorNextPage来获取更多数据到流中。这不是一个好主意。您应该认为单个订阅将返回单个 REST 调用的所有结果,然后调用OnComplete. 如果您想调用新的 REST 调用,则只需再次订阅。

此外,代码中没有清楚地表达单个订阅调用的语义。所以你需要考虑维护你的代码。当您将来查看代码时,您可能会认为语义是什么?我建议单个订阅的语义映射到单个 REST 调用的可能性更大。否则,您的代码可能会更加混乱。

更进一步,你应该避免使用单一订阅模型,因为如果抛出任何异常,那么你的 observable 就完成了,当然,调用 Web 服务很容易出错。如果多订阅模式出现错误,您可以更轻松地恢复。

我也会避免IObservable<T> Resources { get; },因为它建议某种“固定”值,而不是它更具动态性 - 换句话说,每个调用可能会给你不同的值。最好调用GetResources方法而不是Resources属性。

一些,底线,我有一个IObservable<T>抽象一个对你的底层 REST 服务的调用。

于 2012-08-14T01:38:30.520 回答
0

您在这里结合了两个真正应该单独解决的问题。

首先是您的代码从其他来源获取数据。第二个是在有新数据可用时将该数据发布给相关方。

关于第一个,反应式扩展不会有帮助。您在这里关心的是按时间间隔获取数据;它必须是一个定时间隔,因为在您的代码中调用 REST 服务时,没有回调,您没有什么可以挂钩服务可以调用的。

如果外部服务对您的代码进行了某种回调,则可以将其包装在某个IObservable<T>实现中,然后您可以订阅并执行您的操作(实际上只是转发订阅)。

对于第一个问题,您可以使用 Reactive Extensions 的唯一方法是使用上的静态Timer方法来设置计时器。Observable

对于第二个问题(在您拥有数据并且想要通知订阅者之后),您绝对可以并且应该使用IObservable<T>实现来通知订阅者。

在这种情况下,我强烈建议您不要尝试偏离接口上Subscribe方法的意图。IObservable<T>您应该公开一个方法,该方法将为您提供IObservable<T>任何人都可以订阅的方法(调用IObservable<T>之前是否热或冷Subscribe取决于您)并通过调用调用返回的接口实现上的Dispose方法来取消订阅。IDisposableSubscribe

这样,您的客户可以获取IObservable<T>、订阅他们想要的通知,然后在完成后取消订阅。

于 2012-08-13T17:35:23.160 回答