2016-07-22 9 views
3

非同期コード補完ブロックを頻繁に使用するAPIを設計しています。UIスレッドのコールバック用OPTIONALLYデザインパターン

public interface IResult<T extends Result.I> { 
    void onResult(T); 
} 

public void doXYZ(IResult<Result.TypeA> iResult) { ... } 

ユーザーは、私のAPIのdoXYZ()を呼び出してしまうと、別のネットワークワーカースレッドが後でiResult.onResult()を呼び出します。時には彼はonResult()が呼び出されたスレッドを気にしません。UIを更新するだけの場合もあります。ユーザーの負担を軽減し、匿名の内部クラスをきれいに保つことができます。小さい。

このAPIはAndroid用で、多くの場合(すべてではありません)、UI要素に影響を与えるonResult()コールバックで何か操作を行い、コードがUIスレッド上で実行されることが必要な場合があります。 runOnUIThread(...)の呼び出しでコードをダーティにすることをユーザーに負わせるのではなく、doXYZ()の呼び出し時に、 UIスレッドでコールバックを呼び出すかどうかを指定します。

  1. パフォーマンス上の理由から、私のAPIが常にUIスレッドでonResult()を呼び出さないようにしたいと思います。

  2. 私が見た1つのパターンは、doXYZ(...、boolean callOnUIThread)メソッドパラメータを追加することです。しかし、APIが文書化されているので、私はむしろそれらの追加のブール値をすべて持つことによって、ドキュメンテーション(およびメソッドシグネチャ)を汚してはいけません。

  3. 別の考えでは、各doXYZ()がcallOnUIThreadパラメータのあるものと1つを持つようにオーバーロードされていましたが、膨大なためにドキュメント化に非常に悪いです。

  4. もう1つは、onResult()メソッドにonResult()に加えてonResultUI()メソッドを追加することでしたが、ユーザーのコードを匿名クラスで常に定義する必要があるため、

これを達成するためのクリーンな方法の提案は、次のとおりです。 i。簡潔 ii。コードの可読性には最適 iii。文書化が容易 ?

+0

は使用コードについて考えてみます:コードは、GUIスレッド上で実行する必要がある場合は、 'IResult'インスタンスを作成した時点で知っていますか?その場合、GUIインターフェース 'IRunsOnGui'を提供することができます。これは、クライアントが' onResult'をGUIスレッド上で実行したい場合に拡張することができます。あなたが 'IResults'を追加するとき、それが' IRunsOnGui'のインスタンスであるかどうかをチェックし、その結果がGUIスレッド上でのみ実行できるようにします。これの一例は[ここのideone](http://ideone.com/whEDB2)で見ることができます。これがあなたの質問に答えるなら、私は答えに入れてうれしいです。 – BeyelerStudios

+0

したがって、基本的に 'doXYZ'はインタフェースを介して結果を報告する非同期ジョブをディスパッチしています。この場合、マーカとデコレータの両方が適しています(私の[ideone-link](http://ideone.com/whEDB2)で見るように組み合わせることもできます):例では、Foremanボブはディスパッチを行います、 'bob.dirve 'あなたの' doXYZ 'になるでしょう)。あなたが好きなものを選んでください。「IResult」を装飾するか、別の方法で動くようにマーキングすることで、呼び出し先にコントロールを与えます。 'doXYZ'では、あなたの一般的な作業者のプールに送ってもらうか、GUIスレッドに送るかをチェックしてください。 – BeyelerStudios

答えて

2

IResultのデコレータパターンを使用してください。

など。あなたがインターフェイスIResultを持っている場合は、あなたが飾られていることを保証デコレータを作成することができます

interface IResult<T> { 
    void onResult(T result); 
} 

この

class PrintCurrentThreadAndResult implements IResult<String> { 
    @Override 
    public void onResult(String result) { 
    Thread thread = Thread.currentThread(); 
    System.out.print(thread.getName()); 
    System.out.print(" - "); 
    System.out.println(result); 
    } 
} 

のような結果コールバックの実装(私は、デモ用に簡単ジェネリック型Tを作りました)結果は特別なスレッド(例えば、UIスレッド)上で呼び出されます。誰もが簡単にコンパイルしてテストできるように、ここでスイングのイベントディスパッチャスレッドを使用します。

class UIThreadAwareResult<T> implements IResult<T> { 

    private IResult<T> delegate; 

    public UIThreadAwareResult(IResult<T> delegate) { 
    this.delegate = delegate; 
    } 

    @Override 
    public void onResult(T result) { 
    invokeOnUIThread(result); 
    } 

    private void invokeOnUIThread(final T result) { 
    try { 
     EventQueue.invokeAndWait(new Runnable() { 
     @Override 
     public void run() { 
      delegate.onResult(result); 
     } 
     }); 
    } catch (Exception e) { 
     throw new RuntimeException(e); 
    } 
    } 
} 

クライアントコードは、元の結果を飾るだけで実行するスレッドを選択できます。

public class Main { 

    public static void main(String[] args) { 
    Main main = new Main(); 

    IResult<String> result = new PrintCurrentThreadAndResult(); 
    main.doXYZ(result); 

    IResult<String> uiThreadAwareResult = new UIThreadAwareResult<String>(result); 
    main.doXYZ(uiThreadAwareResult); 
    } 

    public void doXYZ(IResult<String> iResult) { 
    iResult.onResult("Hello"); 
    } 
} 

出力は

main - Hello 
AWT-EventQueue-0 - Hello 
+1

@BeyelerStudios OPのdoXYZメソッドがどのように実装されているのかわからないので、私は 'invokeAndWait'を使います。 'doXYZ'メソッドはまず何らかの結果を計算し、それを' IResult'に渡し、最後に 'onResult'メソッドと同期させる必要がある何かを実行するかもしれません。 –

+0

@BeyelerStudios 'ワーカースレッドでも実行する'とはどういう意味ですか? –

+0

私はOPの*非同期コード補完ブロックを大量に使用するAPIを読んでいます。彼は非同期計算を実行していて、結果を処理する方法(onResult')のインターフェースを提供していたり​​、何とか 'onResult'を非同期にディスパッチしています。デコレータはどちらの場合もワーカースレッドで 'invokeAndWait'を実行するので、コード補完は実際には非同期ではありません。 – BeyelerStudios

関連する問題