Javaにおけるコールバックパターン:非同期通信の習得
別名
- コールアフター
- イベントサブスクリプション
- リスナー
コールバックデザインパターンの目的
Javaコールバックデザインパターンは、他のコードに引数として渡される実行可能なコードであり、そのコードは都合の良い時に引数を呼び戻す(実行する)ことが期待されています。
実例を用いたコールバックパターンの詳細な説明
現実世界の例
コールバックデザインパターンの現実世界のアナロジーは、飲食業界で見つけることができます。混雑したレストランで注文をする状況を想像してみてください。料理の準備が出来るまでカウンターで待つ代わりに、レジ係に電話番号を伝えます。注文が準備できると、キッチンスタッフが電話またはテキストメッセージで、食事の受け取り準備ができたことを知らせます。
このアナロジーでは、注文をすることは非同期タスクを開始することに相当します。電話番号を伝えることは、コールバック関数を渡すことに相当します。キッチンで料理を準備することは非同期処理を表し、受信する通知はコールバックが実行されることを表し、何もせずに待つことなく食事を受け取ることができます。このタスクの開始と完了の分離が、コールバックデザインパターンの本質です。
簡単に言うと
コールバックとは、定義された時点で呼び出される実行者に渡されるメソッドです。
Wikipediaによると
コンピュータープログラミングにおいて、コールバック(「コールアフター」関数とも呼ばれる)とは、他のコードに引数として渡される実行可能なコードです。その他のコードは、特定の時点で引数を呼び戻す(実行する)ことが期待されます。
Javaにおけるコールバックパターンのプログラミング例
実行タスクが完了した後に通知を受ける必要があります。実行者にコールバックメソッドを渡し、呼び戻されるのを待ちます。
Callback
は、単一のメソッドを持つシンプルなインターフェースです。
public interface Callback {
void call();
}
次に、タスクの実行が完了した後にコールバックを実行するTask
を定義します。
public abstract class Task {
final void executeWith(Callback callback) {
execute();
Optional.ofNullable(callback).ifPresent(Callback::call);
}
public abstract void execute();
}
@Slf4j
public final class SimpleTask extends Task {
@Override
public void execute() {
LOGGER.info("Perform some important activity and after call the callback method.");
}
}
最後に、タスクを実行し、完了時にコールバックを受け取る方法を示します。
public static void main(final String[] args) {
var task = new SimpleTask();
task.executeWith(() -> LOGGER.info("I'm done now."));
}
プログラム出力
17:12:11.680 [main] INFO com.iluwatar.callback.SimpleTask -- Perform some important activity and after call the callback method.
17:12:11.682 [main] INFO com.iluwatar.callback.App -- I'm done now.
Javaでコールバックパターンを使用する場合
コールバックパターンを使用する状況
- GUIアプリケーションやイベント駆動型システムにおける非同期イベント処理
- 特定のイベントが他のコンポーネントのアクションをトリガーする必要がある場合の通知メカニズムの実装
- 互いに直接依存することなくやり取りする必要があるモジュールやコンポーネントのデカップリング
Javaにおけるコールバックパターンの現実世界のアプリケーション
- GUIフレームワークは、ユーザーインタラクション(クリック、キー押下など)のイベント処理にコールバックを頻繁に使用します。
- Node.jsは、ノンブロッキングI/O操作にコールバックを大きく依存しています。
- JavaScriptのPromiseなど、非同期操作を扱うフレームワークは、非同期タスクの解決または拒否を処理するためにコールバックを使用します。
- CyclicBarrierコンストラクタは、バリアがトリップされるたびにトリガーされるコールバックを受け入れることができます。
コールバックパターンのメリットとデメリット
メリット
- 操作の実行ロジックとシグナリングまたは通知ロジックをデカップリングし、モジュール性と再利用性を向上させます。
- 非同期処理を促進し、アプリケーションの応答性とスケーラビリティを向上させます。
- コンポーネントがイベントの発生時に反応できるリアクティブプログラミングモデルを可能にします。
デメリット
- コールバックヘルまたはピラミッドオブドゥーム:深くネストされたコールバックは、読みやすく保守しにくいコードにつながる可能性があります。
- 制御の反転により、コードの流れが追跡しにくくなり、デバッグがより困難になる可能性があります。
- 特に例外が使用される言語や環境では、エラー処理に関する潜在的な問題があります。エラーはコールバックを通じて伝播する必要がある可能性があります。
関連するJavaデザインパターン
- コマンド:コールバック操作でより柔軟性または状態が必要なシナリオでは、コールバックオブジェクトをコマンドオブジェクトとして実装できます。
- オブザーバー:コールバックは、コールバック関数を動的に購読および購読解除できるため、オブザーバーパターンのより動的で軽量な形式と見なすことができます。
- プロミス:一部の言語やフレームワークでは、プロミスまたはフューチャを使用して、非同期操作をよりクリーンに処理できます。成功または失敗の場合には、多くの場合コールバックを使用します。