2016-07-03 7 views
5

Ich habe ein Spiel (basierend auf monogame/XNA) mit einer Update-Methode wie folgt:Wie kann ich ein Abfragesystem in ein Rx.Net IObservable verwandeln?

public void Update(GameTime gameTime) 
{ 
    component.Update(gameTime); 
} 

Ich würde dies das Reactive Muster umwandeln möge. Meine aktuelle Lösung ist:

public void Initialize() 
{ 
    updateSubject = new Subject<GameTime>(); 

    component = new Component(); 

    updateSubject.Subscribe((gameTime) => component.Update(gameTime)); 
} 

public void Update(GameTime gameTime) 
{ 
    updateSubject.OnNext(gameTime); 
} 

Ich bin neu in Rx, also lerne ich immer noch den besten Weg, Dinge zu tun. Ich habe gelesen, dass Subject vermieden werden sollte und stattdessen Observable.Create verwendet werden sollte.

Ist Subject hier geeignet? Wie kann ich in diesem Fall Observable.Create verwenden?

Antwort

6

Das Hauptproblem, mit dem Sie konfrontiert sind, ist, dass Sie eine Quelle für Ihre Observable benötigen. Im Allgemeinen können Sie Observables aus einer Vielzahl von Quellen erstellen, z. B. Ereignisse, Delegaten, Aufgaben, viele der beobachtbaren Erweiterungen (wie .Interval oder .Generate) und Themen.

In Ihrem Fall müssen Sie eine Quelle haben, die Sie Code haben können, extern zu Ihrer Observable, Push-Werte zu. In diesem Fall ist ein Thema völlig in Ordnung, aber Sie könnten auch einen Delegierten verwenden.

Wenn Sie ein Thema verwenden, ist Ihr Code in Ordnung. Der einzige Nachteil ist, dass Sie updateSubject.OnCompleted aufrufen und das Observable beenden können.

Wenn Sie einen Delegaten verwenden möchten, dann könnte Ihr Code wie folgt aussehen:

private Action<GameTime> updateGameTime = null; 

public void Initialize() 
{ 
    component = new Component(); 

    Observable 
     .FromEvent<GameTime>(a => updateGameTime += a, a => updateGameTime -= a) 
     .Subscribe((gameTime) => component.Update(gameTime)); 
} 

public void Update(GameTime gameTime) 
{ 
    updateGameTime(gameTime); 
} 

Auf diese Weise das einzige, was Sie mit updateGameTime tun kann, ist in einer neuen GameTime passieren - man kann nicht „aus Versehen "Beenden Sie die Sequenz.

Jetzt ist das ganze Problem mit der Verwendung von Themen im Vergleich zu Observable.Create einer der Staat. In deinem Code brauchst du den Status, also ist ein Thema in Ordnung. Im Allgemeinen, und wann immer es möglich ist, ist es ratsam, den Zustand einzukapseln - und das ist es, was Observable.Create für Sie tut.

Nehmen Sie dieses Beispiel:

var i = -1; 
var query = 
    Observable 
     .Range(0, 10).Select(x => 
     { 
      i = -i * 2; 
      return x * i; 
     }); 

Wenn ich auf diese beobachtbaren abonnieren zweimal ich diese beiden Sequenzen erhalten:

(1)

 
0 
-4 
16 
-48 
128 
-320 
768 
-1792 
4096 
-9216 

(2)

 
0 
-4096 
16384 
-49152 
131072 
-327680 
786432 
-1835008 
4194304 
-9437184 

Die Reihenfolge ändert sich weil ich den Staat benutzt habe (d.h. var i = -1;).

Hätte ich den Code mit Observable.Create geschrieben ich diesen Zustand vermeiden könnte:

var query = 
    Observable 
     .Create<int>(o => 
     { 
      var i = -1; 
      return 
       Observable 
       .Range(0, 10).Select(x => 
       { 
        i = -i * 2; 
        return x * i; 
       }) 
       .Subscribe(o); 
     }); 

Es ist immer noch die gleiche Abfrage, aber der Staat ist gekapselt, also wenn ich jetzt zweimal abonniere ich bekommen:

(1)

 
0 
-4 
16 
-48 
128 
-320 
768 
-1792 
4096 
-9216 

(2)

 
0 
-4 
16 
-48 
128 
-320 
768 
-1792 
4096 
-9216 

Es gibt Zeiten, wenn komplexe Abfragen geschrieben werden, die Sie vielleicht denken, dass die Verwendung eines Betreffs es viel einfacher machen würde und im Allgemeinen Fehler auftreten. Sie sollten immer versuchen, einen reinen Operatoransatz zu finden, bevor Sie in diesem Fall Subjekte verwenden. Wenn Sie dann nicht die Verwendung eines Betreffs in Observable.Create kapseln können.

Es ist Zeiten wie Ihre, dass die Verwendung eines Betreffs in Ordnung ist, weil Sie diesen externen Zustand benötigen.

0

Nur darauf hinweisen, dass Sie nicht sinnlos Code Rx verwenden.

public void Initialize() 
{ 
    //updateSubject = new Subject<GameTime>(); 

    component = new Component(); 

    //updateSubject.Subscribe((gameTime) => component.Update(gameTime)); 
} 

public void Update(GameTime gameTime) 
{ 
    //updateSubject.OnNext(gameTime); 
    component.Update(gameTime) 
} 

Hier habe ich die Subject entfernt und rufen Sie einfach direkt durch die Update Methode s component, um den Punkt zu veranschaulichen.

Vielleicht suchen Sie eine private Methode der Umfrage? In diesem Fall könnte Observable.Interval ein guter Anfang sein.

+1

Ich gab ein minimales Beispiel für SO. Der echte Code ist komplexer als das. – sdgfsdh

+0

Das ist gut zu hören. Aber wenn dies ein vollständiges minimales nachprüfbares Beispiel ist, dann ist der Subjekt (und somit Rx) überflüssig. Ich glaube nicht, dass Sie genügend Informationen liefern, um eine vernünftige Antwort zu geben. –

+1

Ein Beispiel dafür, wo mein 'IObservable ' nützlich ist, ist die Verarbeitung der Eingabe. Wenn ich auch einen 'IObservable ' habe, kann ich es mit meinem 'GameTime'-Stream anzeigen. – sdgfsdh

Verwandte Themen