我应该在我的接口上公开IObservable<T>吗?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (37)

我和我的同事有争执。我们正在编写一个处理大量数据的.NET应用程序。它接收数据元素,将它们的子集按照一定的准则分组为块,并对这些块进行处理。

假设我们有类型的数据项Foo一个接一个地到达某个来源(例如从网络)。我们想聚集子集相关的类型对象Foo,构造一个类型的对象。Bar从每个这类子集和类型的进程对象中提取。Bar

我们中的一个建议了以下设计。它的主题是揭露IObservable<T>对象直接来自组件的接口。

// ********* Interfaces **********
interface IFooSource
{
    // this is the event-stream of objects of type Foo
    IObservable<Foo> FooArrivals { get; }
}

interface IBarSource
{
    // this is the event-stream of objects of type Bar
    IObservable<Bar> BarArrivals { get; }
}

/ ********* Implementations *********
class FooSource : IFooSource
{
    // Here we put logic that receives Foo objects from the network and publishes them to the FooArrivals event stream.
}

class FooSubsetsToBarConverter : IBarSource
{
    IFooSource fooSource;

    IObservable<Bar> BarArrivals
    {
        get
        {
            // Do some fancy Rx operators on fooSource.FooArrivals, like Buffer, Window, Join and others and return IObservable<Bar>
        }
    }
}

// this class will subscribe to the bar source and do processing
class BarsProcessor
{
    BarsProcessor(IBarSource barSource);
    void Subscribe(); 
}

// ******************* Main ************************
class Program
{
    public static void Main(string[] args)
    {
        var fooSource = FooSourceFactory.Create();
        var barsProcessor = BarsProcessorFactory.Create(fooSource) // this will create FooSubsetToBarConverter and BarsProcessor

        barsProcessor.Subscribe();
        fooSource.Run(); // this enters a loop of listening for Foo objects from the network and notifying about their arrival.
    }
}

另一种设计建议,其主题是使用我们自己的Publisher接口,并且只有在需要时才在实现中使用Rx。

//********** interfaces *********

interface IPublisher<T>
{
    void Subscribe(ISubscriber<T> subscriber);
}

interface ISubscriber<T>
{
    Action<T> Callback { get; }
}


//********** implementations *********

class FooSource : IPublisher<Foo>
{
    public void Subscribe(ISubscriber<Foo> subscriber) { /* ...  */ }

    // here we put logic that receives Foo objects from some source (the network?) publishes them to the registered subscribers
}

class FooSubsetsToBarConverter  : ISubscriber<Foo>, IPublisher<Bar>
{
    void Callback(Foo foo)
    {
        // here we put logic that aggregates Foo objects and publishes Bars when we have received a subset of Foos that match our criteria
        // maybe we use Rx here internally.
    }

    public void Subscribe(ISubscriber<Bar> subscriber) { /* ...  */ }
}

class BarsProcessor : ISubscriber<Bar>
{
    void Callback(Bar bar)
    {
        // here we put code that processes Bar objects
    }
}

//********** program *********
class Program
{
    public static void Main(string[] args)
    {
        var fooSource = fooSourceFactory.Create();
        var barsProcessor = barsProcessorFactory.Create(fooSource) // this will create BarsProcessor and perform all the necessary subscriptions

        fooSource.Run();  // this enters a loop of listening for Foo objects from the network and notifying about their arrival.
    }
}

你觉得哪个更好?

提问于
用户回答回答于

公开IObservable<T>不影响任何形式的Rx设计。实际上,设计决策与在公开旧的.NET事件还是滚动你自己的发布/子机制之间是完全相同的。唯一的区别是IObservable<T>是新概念。

需要证据吗?看看F#,它也是一种.NET语言,但比C语言还年轻。在F#中,每个事件都来自IObservable<T>。老实说,我认为抽象出一个非常合适的.NET pub/sub是没有意义的--即IObservable<T>-取消你的pub/sub级抽象。只要公开IObservable<T>

滚动自己的pub/sub抽象感觉就像将Java模式应用到.NET代码中一样。不同的是,在.NET中,对观察者模式一直有很好的框架支持,而且根本不需要自己的框架。

用户回答回答于

首先,值得注意的是IObservable<T>mscorlib.dllSystem命名空间,因此公开它在某种程度上相当于公开IComparable<T>IDisposable。这相当于选择.NET作为您的平台,您似乎已经这样做了。

现在,我想提出一个不同的问题。

你是在问:我们是否要在整个系统内推广分散使用Rx操作员?。显然,这并不是很吸引人,因为可能从概念上将Rx视为第三方库。

不管是哪种方式,答案并不在于你们两个提出的基本设计,而在于这些设计的用户。我建议将您的设计分解到抽象级别,并确保Rx操作符的使用范围仅限于一个级别。当我谈到抽象级别时,我指的是类似于OSI模型,仅在同一应用程序的代码中。

扫码关注云+社区

领取腾讯云代金券