2011-04-13 145 views
1

我想知道从构架的角度来看,它是否可以将主题传递给组件。我真正想要的是让组件暴露一个可观察的事物。但是,我想控制这个可观察流来自哪里,这就是为什么我问是否可以通过组件可以引发“事件”的主题。可以将主题传递给组件

好吧,我们来详细说明一下。假设我们正在设计一个组件,它接受用户输入,控制击键并显示结果列表。实际的搜索发生在另一个服务组件上。

我想设计SearchWidget创建者函数是这样的:

//notice how I just avoided the word "constructor". However, conside this code as 
//language agnostic. Could be RxJs or Rx .NET. It's Rx(ish)! 

function SearchWidget(userInputStream, resultStream){ 
    // do some funky Rx hotness! 

} 

更高水平的部件(比方说控制器/介体)实际上将挂钩流。

显然,resultStream需要使用inputStream来完成工作。

在我们上面的例子中,resultStream从SearchWidget的角度来看就是一个简单的observable,它可以监听结果列表。但是,它将作为更高级别组件中的Subject实现。

相比之下,userInputStream将成为SearchWidget视角的主题,但它将在更高的组件级别上实例化,因为我们事先需要它来获取resultStream。尽管从更高层次的角度来看,它是一个简单的可观察的事物。

高阶代码可能是这样的:

//This code lives in a higher order component (say a controller/mediator) 
var resultStream = new Rx.Subject(); 
var userInputStream = new Rx.Subject(); 
userInputStream 
    .Throttle(500) 
    .DistinctUntilChanged() 
    .Select(service.search) //service comes from somewhere. 
    .Switch() 
    .Subscribe(resultStream.OnNext, 
       resultStream.OnError, 
       resultStream.OnCompleted); 


var searchWidget = new SearchWidget(userInputStream, resultStream.AsObservable()); 

在执行上面的,我用前SearchWidget初始化的userInputStream 。当然,我也可以实现这样说:

//implementation of the search widget 
function SearchWidget(resultStream){   
    var userInputStream = new Rx.Subject(); 
    // provide something like getUserInputStream() 
    // that will return unserInputStream.AsObservable() 

    // do some funky Rx hotness! 
} 

//This code lives in a higher order component (say a controller/mediator) 
var resultStream = new Rx.Subject(); 
var searchWidget = new SearchWidget(resultStream); 

//we need to initialize the searchWidget in advance to get the userInputStream 

searchWidget 
    .getUserInputStream() 
    .Throttle(500) 
    .DistinctUntilChanged() 
    .Select(service.search) //service comes from somewhere. 
    .Switch() 
    .Subscribe(resultStream.OnNext, 
       resultStream.OnError, 
       resultStream.OnCompleted); 

所以,从封装的角度来看,第二个实现可能更强劲。然而,通过这个主题提供了更丰富的灵活性。

由于使用事件流的概念非常现代,所以在设计具有事件流的应用程序时,我很难找到最佳实践以获得更大的图片。

回答

1

由于使用事件流的概念非常现代,所以在设计带有事件流的应用程序时,我很难找到最佳实践。

当然,在边界上很酷,但这也意味着你必须在你走的时候发现“正确的方式”!因此,请记住ISubject既是一个IObserver(发布部分),也是一个IObservable(订阅部分) - 如果你的意图是你的方法的客户端应该是订阅者,那么只给它们IObservable部分(即转换Subject到IObservable),如果你的方法的客户端应该是发布者,给他们IObserver部分。

当你使用Observable时,你会看到同样的结果。CreateWithDisposable(),你给的东西是IObserver位(因为你正在创建一个IObservable,你的工作是发布的东西!)

2

对我来说,它看起来只需要一点改组对于什么是最明确的方式来表达正在发生的事情(Rx可能很容易被滥用)有点思考。

看着你的例子,我发现将用户输入暴露为IObservable(通过你的GetUserInputStream)没有任何问题,并且在继续处理更高级别的控制器/调解器中的流时也没有错,但对于我来说,需要传递resultStream Subject。我看不到任何原因,您不能在SearchWidget上使用常规方法来处理结果。喜欢的东西:

var searchWidget = new SearchWidget(); 

searchWidget 
    .GetUserInputStream() 
    .Throttle(500) 
    .DistinctUntilChanged() 
    .Select(service.search) //service comes from somewhere. 
    .Switch() 
    .Subscribe(result => searchWidget.HandleSearchResult(result), 
       ex => searchWidget.HandleSeachError(ex), 
       () => searchWidget.HandleSearchComplete()); 

这是一个很大更加明确,你就可以在一个更清晰的方式来表达,通过精心命名的方法,什么结果将在SearchWidget。

如果你确实想通过Rx处理这些响应的内部结构,那么在内部实例化一个主题并处理来自方法调用的响应没有任何问题。如:

public class SearchWidget 
{ 
    private ISubject subject; 

    public SearchWidget() 
    { 
     this.subject = new Subject(); 

     //do funky rx stuff on the subject here 
    } 

    public void HandleSearchResult(SearchResult result) 
    { 
     subject.OnNext(result); 
    } 

    public void HandleSearchError(Exception ex) 
    { 
     subject.OnError(ex); 
    } 

    public void HandleSearchComplete() 
    { 
     subject.OnCompleted(); 
    } 

    public IObservable<MouseEvent> GetUserInputStream() 
    { 
     return someUserInputStream; // whatever your stream is 
    } 

} 
+0

谢谢您的回答。但是,我没有得到它。什么是你的代码中的“someUserInputStream”?你实际上是否指“主题”?如果是这样,你正在从外部提出通知,看起来实际上是为了注入结果。另外请注意,在您的实现中,我仍然需要提前初始化小部件。这是我想避免的。然而,更大的画面更加复杂,我只是简单地举例说明。无论如何,我从讨论中学到了一些东西。我认为一般来说,这个问题应该是内部的,因为我们希望避免(1/2) – Christoph 2011-04-14 20:20:59

+0

(2/2)其他人提出他不应该拥有的流的通知。但是,这不是我的目标。我的目标是能够在另一个组件初始化之前将流连接在一起,并且我认为我将以这种方式行走,看看它是怎么回事... – Christoph 2011-04-14 20:23:50

+0

@Christoph - someUserInputStream表示通常由getUserInputStream()返回的内容。这只是为了你现在使用的任何东西。它可能真的是任何事件的流。 – 2011-04-15 07:52:51