是否可以将主题传递到组件中



我想知道从架构的角度来看,将主题传递到组件中是否ok。我真正想要的是让组件公开一个可观察对象。然而,我想控制这个可观察流来自哪里,所以这就是为什么我问是否可以在组件可以引发"事件"的地方传递一个主题。

好的,让我们详细说明一下。

假设我们正在设计一个组件,该组件接受用户输入,限制击键并显示结果列表。实际的搜索正在另一个服务组件上进行。

我想这样设计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来完成工作。

在上面的示例中,从SearchWidget的角度来看,resultStream将是一个简单的可观察对象,它可以监听结果列表。但是,它将在更高级的组件中作为Subject实现。

相反,从SearchWidget的角度来看,userInputStream将是一个主题,但它将在更高的组件级别上实例化,因为我们需要提前将它与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);

因此,从封装的角度来看,第二个实现可能看起来更健壮。然而,传入主题提供了更丰富的灵活性。

由于使用事件流的概念是相当现代的,所以在设计使用事件流的应用程序时,我正在努力寻找更大范围的最佳实践。

对我来说,它看起来只是需要一点重新洗牌和一点思考,什么是最清晰的方式来表达正在发生的事情(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
   }
}

由于使用事件流的概念是相当现代的,所以在设计使用事件流的应用程序时,我正在努力寻找更大范围的最佳实践。

当然,站在前沿很酷,但这也意味着你必须在前进的过程中发现"正确的道路"!

所以,记住issubject既是一个IObserver(发布部分),也是一个IObservable(订阅部分)——如果你的意图是你的方法的客户端应该是订阅者,只给他们IObservable部分(即将Subject转换为IObservable),如果你的方法的客户端应该是发布者,给他们IObserver部分。

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

相关内容

  • 没有找到相关文章

最新更新