43

非ブロッキング メソッド呼び出しのネストされたシーケンスを作成するための Java パターンを探しています。私の場合、一部のクライアントコードは、サービスを非同期的に呼び出してユースケースを実行する必要があり、そのユースケースの各ステップ自体を非同期で実行する必要があります (この質問の範囲外の理由により)。次のような既存のインターフェースがあるとします。

public interface Request {} 

public interface Response {} 

public interface Callback<R extends Response> {
    void onSuccess(R response);
    void onError(Exception e);
}

+ (クライアントによって与えられる)、+ (サービスによって内部的に使用される) など、RequestResponseインターフェースのさまざまな対の実装があります。RequestAResponseARequestBResponseB

処理の流れは次のようになります。

ネストされたコールバックを示すシーケンス図。

各応答の受信と次の要求の送信の間に、いくつかの追加処理が発生する必要があります (たとえば、前の要求または応答のいずれかの値に基づいて)。

これまでのところ、これを Java でコーディングするために 2 つのアプローチを試しました。

  • 匿名クラス: ネストが必要なため、すぐに見苦しくなります
  • 内部クラス: 上記よりもすっきりしていますが、他の開発者が実行の流れを理解するのは依然として困難です

このコードを読みやすくするためのパターンはありますか? たとえば、サービス メソッドを、ネストを処理するフレームワーク クラスによって順番に実行される自己完結型の操作のリストとして表現できますか?

4

4 に答える 4

13

実装 (インターフェイスだけでなく) がブロックされてはならないので、リストのアイデアが気に入っています。

「操作」(おそらくFutures?) のリストを設定します。その設定はかなり明確で読みやすいものでなければなりません。次に、各応答を受信したら、次の操作を呼び出す必要があります。

少し想像すると、これは責任の連鎖のように聞こえます。私が想像しているものの擬似コードは次のとおりです。

public void setup() {
    this.operations.add(new Operation(new RequestA(), new CallbackA()));
    this.operations.add(new Operation(new RequestB(), new CallbackB()));
    this.operations.add(new Operation(new RequestC(), new CallbackC()));
    this.operations.add(new Operation(new RequestD(), new CallbackD()));
    startNextOperation();
}
private void startNextOperation() {
    if ( this.operations.isEmpty() ) { reportAllOperationsComplete(); }
    Operation op = this.operations.remove(0);
    op.request.go( op.callback );
}
private class CallbackA implements Callback<Boolean> {
    public void onSuccess(Boolean response) {
        // store response? etc?
        startNextOperation();
    }
}
...
于 2012-05-24T05:56:37.420 に答える
7

私の意見では、この種の問題をモデル化する最も自然な方法は、を使用することFuture<V>です。

したがって、コールバックを使用する代わりに、「サンク」を返すだけFuture<Response>です。これは、将来のある時点で利用可能になる応答を表します。

次に、後続のステップをのようにモデル化するか、GuavaからFuture<ResponseB> step2(Future<ResponseA>)使用できます。ListenableFuture<V>次に、Futures.transform()またはそのオーバーロードの1つを使用して、関数を自然な方法でチェーンできますが、非同期の性質は維持されます。

このように使用Future<V>すると、モナドのように動作します(実際、頭のてっぺんからはわかりませんが、1つと見なされる可能性があります)。したがって、プロセス全体は、実行されたHaskellのIOのように感じます。 IOモナド経由。

于 2012-05-22T06:56:15.190 に答える
2

アクター コンピューティング モデルを使用できます。あなたの場合、クライアント、サービス、およびコールバック [BD] はすべてアクターとして表すことができます。

Java 用の多くのアクター ライブラリがあります。ただし、それらのほとんどは重量があるため、コンパクトで拡張可能なdf4jを作成しました。アクター モデルをより一般的なデータフロー コンピューティング モデルの特定のケースと見なし、その結果、ユーザーは新しいタイプのアクターを作成して、ユーザーの要件に最適に適合させることができます。

于 2012-05-22T05:00:03.467 に答える
1

あなたの質問を正しく受け取れるかどうかわかりません。サービスを呼び出したい場合、その完了時に、結果を使用して処理を続行できる他のオブジェクトに結果を渡す必要があります。Composite と Observer を使用してこれを実現できます。

于 2012-05-22T07:32:32.207 に答える