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の観点から単純に観察可能になります。ただし、上位レベルのコンポーネント内でサブジェクトとして実装されます。

対照的に、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);

したがって、カプセル化の観点からは、2番目の実装はより堅牢に見える可能性があります。ただし、件名を渡すと、柔軟性が高まります。

イベントストリームを使用するという概念は非常に現代的であるため、イベントストリームを使用してアプリケーションを設計するときに、全体像のベストプラクティスを見つけるのに苦労しています。

4

2 に答える 2

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
   }

}
于 2011-04-13T20:52:36.423 に答える
1

イベントストリームを使用するという概念は非常に現代的であるため、イベントストリームを使用してアプリケーションを設計するときに、全体像のベストプラクティスを見つけるのに苦労しています。

確かに、フロンティアにいることはクールですが、それはまた、あなたが進むにつれて「正しい道」を発見しなければならないことを意味します!

したがって、ISubjectはIObserver(発行部分)とIObservable(サブスクライブ部分)の両方であることに注意してください。メソッドのクライアントをサブスクライバーにすることを目的としている場合は、IObservable部分のみを指定してください(つまり、SubjectをIObservableにキャストします)。メソッドのクライアントがパブリッシャーである必要がある場合は、IObserverパーツを提供します。

Observable.CreateWithDisposable()を使用しても同じことがわかります。ここで、与えられるのはIObserverビットです(IObservableを作成しているので、あなたの仕事はものを公開することです!)

于 2011-04-13T20:02:57.223 に答える