Commandパターンの概要
前置きが長くなりましたが、ここから本連載の本題に入ります。連載初回である今回は、Commandパターンをラムダ式に置き換えてみます。
Commandパターンは、動作をコマンドオブジェクトとして表すパターンです。典型的な Commandパターンのプログラムには、図1に示すようなクラスおよびインタフェースが登場します。
それぞれのクラス、インタフェースの役割は次のとおりです。
- Command:動作を表すコマンドオブジェクトのインタフェース
- ConcreteCommand:具体的な動作を表すコマンドオブジェクトのクラス
- Receiver:動作の対象となるオブジェクトのクラスあるいはインタフェース
- Invoker:登録されたコマンドオブジェクトを用いて動作を起動するクラス
-
Client:コマンドオブジェクトを生成して
Invokerに登録するクラス
実際のプログラムでは、複数の動作を実装するために、ConcreteCommand に相当するクラスが複数存在することもよくあります。
典型的な Commandパターンのプログラムは、図2に示すようなシーケンスで動作します。
すなわち、Commandパターンのプログラムはおおまかに次の2ステップで動作します。
1. Client がコマンドオブジェクトを作成し、Invoker に登録する2. Invoker を通じてコマンドオブジェクトが表す動作を起動する
Commandパターンを用いている例としては、Java標準の並列処理フレームワークである「Executor」が挙げられます。Executorフレームワークでは、非同期的に実行される動作を「タスク」という単位で表します。このタスクがコマンドオブジェクトであると考えられます。タスクは「エクゼキュータ」に登録されます。タスクを実行するためのスレッドを作成・終了したり、タスクをスレッドに割り当てたりするのは、エクゼキュータの仕事です。このExecutorフレームワークの中で、Commandパターンに登場するそれぞれの役割は次のようなクラス、インタフェースが担っています。
-
Command:タスクを表す
CallableインタフェースおよびRunnableインタフェース -
ConcreteCommand:
CallableインタフェースやRunnableインタフェースを実装してタスクを表すクラス -
Invoker:エクゼキュータを表す
Executorインタフェースを実装する各クラス - Client:エクゼキュータにタスクを登録するクラス
- Receiver:GUIコンポーネントやビューモデルなど、プログラムによって異なる
Executorフレームワークの他にも、JavaFXやSwingのようなGUIツールキットなども、Commandパターンを用いる典型的な例です。GUIツールキットでは、ボタン押下などのイベントを処理するイベントハンドラがコマンドオブジェクトにあたります。
Executorフレームワークや、JavaFX、SwingのようなGUIツールキットは、Commandパターンを用いることで、次のような設計意図を実現していると考えられます。
- フレームワークやGUIツールキットが、コマンドオブジェクトによって表現される具体的な動作を知っている必要がない
- コマンドが登録されるタイミングと、コマンドが実行されるタイミングが分離できる
より高度な応用例としては、実行されたコマンドを記録しておくことにより、アンドゥ、リドゥのような機能を実現することが挙げられます。


