35

私は非同期フレームワークを設計しようとしていますが、コールバック パターンとオブザーバー パターンの長所/短所について人々が考えていることを知りたいと思っていました。

Callback pattern:

//example callback
public interface Callback{
    public void notify(MethodResult result);
}

//example method
public class Worker{
  public void doAsyncWork(Callback callback){
     //do work
     callback.notify(result);
  }
}

//example observer pattern
public interface EventListener{
   public void notify(MethodResult result);

}

public class Worker{
  private EventListener listener;
  public registerEventListener(EventListener listener){
   this.listener=listener;
  }
  public void doAsyncWork(){
     //do work
     listener.notify(result);
  }
}

私は、これらのパターンの両方を使用しているように見えるフレームワークを使用しています。EventListener パターンは、リスナーのリストがないため、一般的なパターンではありません。これは、リスナーの優先順位に関する独自のセマンティクスを持つ CompositeListener を作成することで簡単に実装できます。また、各リスナーへのイベントの配布を処理する方法 (各リスナーとシリアル通知に対して新しいスレッドを生成する方法など) もあります。(私は実際に、これは良い考えだと思います。これは、懸念事項を適切に分離し、標準のオブザーバー/リスナー パターンを改善したものだからです)。

それぞれをいつ使用すべきかについて何か考えはありますか?

なるほど。

4

6 に答える 6

36

コマンド、コールバック、およびオブザーバーのパターンには、異なるセマンティクスがあります。

  • コールバック- 何らかの操作が何らかの結果で終了したことを単一の呼び出し元に通知します
  • オブザーバー- 0 から n の関係者に、何らかのイベント (たとえば、操作の完了) が発生したことを通知します。
  • コマンド- 操作呼び出しをオブジェクトにカプセル化し、ワイヤ経由で転送可能または持続可能にする

あなたの例では、コールバックとオブザーバーの両方のパターンを組み合わせて、API の柔軟性を高めることができます。

  1. コールバックパターンを使用して操作をトリガーし、トリガーされた操作が終了したことを非同期的に呼び出し元に通知します。
  2. イベント/オブザーバーパターンを使用して、他のコンポーネント (操作をトリガーしなかったコンポーネント)に、操作が終了したときに通知を受ける機会を与えます。
于 2012-01-22T08:50:04.120 に答える
26

どちらのパターンも優れており、どちらを選択するかは、何を構築するか、およびフレームワークをどのように使用するかによって異なります。

次の典型的な作業の流れで、ある種のパブリッシュ/サブスクライブ システムを構築しようとしている場合:

  • クライアントは非同期タスクを開始し、それを忘れます
  • タスクが完了すると、複数のハンドラーが通知を受け取ります

パターンはObserverあなたにとって自然な選択です。フレームワークを実行しているので、 EventBusパターンを使用して疎結合を実現することも検討する必要があります。

単純な非同期実行だけが必要で、フレームワークを使用する典型的なフローは次のとおりです。

  • 非同期タスクを開始
  • 完成したら何かをする

また

  • 非同期タスクを開始
  • 何かをする
  • 完了するまで待ってから何かをする

次に、 simple を使用する必要がありますCallback

しかし、より使いやすくクリーンな API を実現するために、Callback抽象化を取り除き、何らかのFuture.

public interface Worker<T> {

    Future<T> doAsync();

}

また、Worker次の方法で使用できます。

Future<Integer> future = worker.doAsync();

// some work here

Integer result = future.get(); // waits till async work is done

Future標準のJava Futureである可能性があります。ただしListenableFuture、guava ライブラリから使用することをお勧めします。

于 2012-01-21T11:58:11.990 に答える
5

コールバック パターンの方が単純であるため、より予測可能であり、独自の変化状態によるバグが発生する可能性が低いと主張したいと思います。動作中のこの例は、GWT がブラウザー/サーバー通信を処理する方法です。

ただし、ジェネリックを使用することもできます。

//example callback
public interface Callback<T> {
    public void notify(T result);
}

//example method
public class Worker{
  public void doAsyncWork(Callback<SomeTypeOrOther> callback){
     //do work
     callback.notify(result);
  }
}
于 2012-01-21T07:14:23.280 に答える