私は非同期フレームワークを設計しようとしていて、コールバックパターンとオブザーバーパターンの賛否両論であると人々が考えていることを知りたいと思っていました。
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を作成し、各リスナーへのイベントの配布を処理する方法によって簡単に実装できます。各リスナーとシリアル通知の新しいスレッドを生成します。 (これは、懸念事項を適切に分離し、標準のオブザーバー/リスナーパターンの改善であるため、実際にはこれは良いアイデアだと思います)。
それぞれをいつ使用すべきかについての考えはありますか?
Thxs。
どちらのパターンも優れており、どちらを選択するかは、何を構築するか、およびフレームワークをどのように使用するかによって異なります。
次の典型的な作業の流れで、ある種のパブリッシュ/サブスクライブシステムを構築しようとしている場合:
その場合、Observer
パターンは自然な選択です。フレームワークを実行しているとき、疎結合を実現するために EventBus パターンの使用も検討する必要があります。
単純な非同期実行だけが必要で、フレームワークを使用する一般的なフローは次のとおりです。
または
次に、単純な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
を使用することをお勧めします。
コマンド、コールバック、オブザーバーのパターンは、セマンティクスが異なります。
あなたの例では、コールバックとオブザーバーの両方のパターンを組み合わせて、APIの柔軟性を高めることができます。
コールバックパターンの方が単純なので、コールバックパターンの方が優れていると思います。つまり、コールバックパターンは予測可能であり、独自の変異状態のためにバグが発生する可能性が低くなります。この動作例は 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);
}
}
両方のパターンは、以下を除いていくつかの共通の意図を共有しています:
観察可能なパターンは複数のリスナーに通知できます。一方、コマンドパターンは、単一のコールバックハンドラーが必要な場合に最適です。
コマンドパターンでは、元に戻す操作を実装するのは簡単です。
乾杯!
特定のコードでは、CallbackとEventListenerの唯一の違いは次のとおりです。
前者はより単純で、後者はより柔軟です。再利用可能なフレームワークを作成している場合は、後者がより理にかなっています。
コマンドデザインパターンは、オブジェクトでアクションを実行するために必要なすべての情報をカプセル化したものであり、イベントの通知に使用されるメカニズムとは関係ありません。