5

次のような更新メソッドを持つゲーム(MonoGame / XNAに基づく)があります:

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

これをリアクティブパターンに変換したいと思います。私の現在の解決策は次のとおりです。

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

    component = new Component();

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

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

私は Rx を初めて使用するので、最善の方法をまだ学んでいます。Subjectこれは避けるObservable.Createべきであり、代わりに使用する必要があると読みました。

Subjectここで適切ですか?

Observable.Createこの場合、どのように使用できますか?

4

2 に答える 2

8

ここで直面している重要な問題は、オブザーバブルのソースが必要だということです。.Interval一般に、イベント、デリゲート、タスク、多くのオブザーバブル拡張 (や など.Generate)、サブジェクトなど、さまざまなソースからオブザーバブルを作成できます。

あなたの場合、オブザーバブルの外部にあるコードを使用して、値をプッシュできるソースが必要です。この場合、サブジェクトはまったく問題ありませんが、デリゲートも使用できます。

サブジェクトを使用する場合、コードは問題ありません。唯一の欠点はupdateSubject.OnCompleted、オブザーバブルを呼び出して終了できることです。

デリゲートを使用する場合、コードは次のようになります。

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);
}

このようにしてできることはupdateGameTime、 new を渡すことだけですGameTime。「誤って」シーケンスを終了することはできません。

現在、主語と対比を使用することに関する全体の問題Observable.Createは、状態の 1 つです。コードでは状態が必要なので、サブジェクトは問題ありません。ただし、一般的には、可能な限り、状態をカプセル化することをお勧めします-それがあなたのObservable.Createために行います。

次の例を見てください。

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

このオブザーバブルを 2 回サブスクライブすると、次の 2 つのシーケンスが得られます。

(1)

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

(2)

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

状態 (つまりvar i = -1;) を使用したため、シーケンスが変わります。

コードを書いていたら、Observable.Createこの状態を避けることができました:

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

これは同じクエリですが、状態はカプセル化されているため、2 回サブスクライブすると次のようになります。

(1)

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

(2)

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

複雑なクエリを作成するときに、サブジェクトを使用するとはるかに簡単になると考える場合があり、一般に、それが間違いの原因です。この場合、主語を使用する前に、常に純粋な演算子のアプローチを見つけるようにしてください。できない場合は、サブジェクトの使用を にカプセル化しますObservable.Create

その外部状態が必要なため、サブジェクトを使用しても問題ない場合があります。

于 2016-07-04T04:15:17.170 に答える
1

コードを不必要に Rx を使用していることを指摘するだけです。

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)
}

ここでは、要点を説明するために、 を削除してsメソッドSubjectを直接呼び出すだけです。componentUpdate

おそらく、ポーリングのプライベートな方法を探していますか? その場合Observable.Interval、開始するのに適した場所になる可能性があります。

于 2016-07-04T06:50:45.693 に答える