我想知道从架构的角度来看是否可以将主题传递给组件。我真正想要的是让组件暴露一个可观察的。但是,我想控制这个可观察流来自哪里,这就是为什么我要问它是否可以传入一个组件可以引发“事件”的主题。
好的,让我们详细说明一下。
比如说,我们正在设计一个获取用户输入,限制击键并显示结果列表的组件。实际搜索发生在另一个服务组件上。
我想像这样设计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,它可以在其上侦听结果列表。但是,它将在更高级别的组件中实现为主题。
相比之下,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());
在上面的实现中,我在之前使用了userInputStream 来初始化SearchWidget。当然我也可以这样实现它:
//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);
因此,从封装的角度来看,第二种实现可能看起来更健壮。但是,传入主题可以提供更丰富的灵活性。
由于使用事件流的概念非常现代,因此在设计具有事件流的应用程序时,我正在努力寻找更全面的最佳实践。
答案 0 :(得分:2)
对我而言,它看起来只是需要进行一些重新洗牌,并想一想最清楚的方式来表达正在发生的事情(Rx很容易被过度使用)。
看看你的例子,我认为将用户输入作为IObservable(通过你的GetUserInputStream)公开没有任何问题,并且继续处理你的更高级别控制器/调解器中的流也没什么不对,但对我来说没有需要传递resultStream主题。我看不出任何理由你不能使用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
}
}
答案 1 :(得分:1)
由于使用事件流的概念非常现代,因此在设计具有事件流的应用程序时,我正在努力寻找更全面的最佳实践。
当然,站在边境是很酷的,但这也意味着你必须随时发现“正确的方法”!
所以,请记住,ISubject既是IObserver(发布部分),也是IObservable(订阅部分) - 如果您的意图是您的方法的客户端应该是订阅者,只给他们IObservable部分(即, IObservable),如果您的方法的客户端应该是Publishers,请为它们提供IObserver部分。
当你使用Observable.CreateWithDisposable()时你会看到同样的事情,你给出的东西是IObserver位(因为你创建了一个IObservable,你的工作就是发布东西!)