Command パターン

出典: フリー百科事典『ウィキペディア(Wikipedia)』
移動: 案内検索

Command パターン: command pattern)はオブジェクト指向プログラミングにおけるデザインパターンの一つで、 動作を表現するオブジェクトを示す。command オブジェクトは、動作とそれに伴うパラメータをカプセル化したものである。

例として、印刷を行うライブラリが PrintJob クラスを備えているとする。ライブラリのユーザーは新たに PrintJob オブジェクトを作成し、パラメータ(印刷するドキュメント、印刷部数など)をセットし、最後にプリンターにジョブを送信するメソッドを呼び出す。

この場合、同じ機能を多数のパラメータを持つ SendJobToPrinter() 関数で提供することができる。command クラスを記述すると、関数を記述するよりコードが多くなるため、クラスを使用するにはそれなりの理由がなければならない。理由として可能性のあるものは多数ある。

  • Command オブジェクトは、手続きに必要なパラメータの一時格納場所として便利である。関数呼び出しのためのパラメータを集めて、後で使用するためにコマンドを保存しておくことができる。
  • クラスはコマンドに関連したコードとデータを集める場所として便利である。コマンドオブジェクトはたとえば名前や機能を呼び出したユーザーといったコマンドについての情報を保持し、予測時間などの処理についての質問に答えることを可能にする。
  • コマンドをオブジェクトとして扱うことにより、複数のコマンドを保持するデータ構造を実現できる。複雑な処理はコマンドオブジェクトからなる木構造グラフ構造として扱うことができる。スレッドプールであれば、ワーカースレッドが使用するコマンドオブジェクトの優先度つきキューを管理することになるだろう。
  • コマンドをオブジェクトとして扱うことで、コマンドオブジェクトが(たとえばスタックに)保存されていればアンドゥ可能な操作を実現できるようになる。
  • コマンドは汎用的なコンポーネントを構築するための抽象化の方法として有用である。たとえば、任意のタイプのコマンドオブジェクトを扱うことができるスレッドプール新しいタイプのコマンドオブジェクトが後で作られても、コマンドは自動的に汎用的なコンポーネントとともに動作する。たとえば、Java において、汎用の ThreadPool クラスがjava.lang.Runnable インタフェース(ThreadPoolExecutor.execute(Runnable task)参照を実装した任意のオブジェクトを受け付けるaddTask(Runnable task) メソッドを持っているような場合である。

Command パターンの使用方法[編集]

Command オブジェクトは下記のような機能を実現するのに便利である:

複数レベルの アンドゥ 
プログラム内の全てのユーザーの操作がコマンドオブジェクトとして実装し、プログラムは最近実行されたコマンドのスタックを保持する。ユーザーがコマンドをアンドゥしたい場合、プログラムは最後に実行されたコマンドオブジェクトをポップし、オブジェクトの undo() メソッドを実行する。
トランザクション的振る舞い 
アンドゥの操作が途中で失敗し、前の状態に巻き戻すことを要求されたときに不可欠である。インストーラやデータベースはこの機能を必要とする。コマンドオブジェクトは2相コミットの実現にも使用できる。
プログレスバー 
プログラムが一連のコマンドを順番に実行する場合を考える。各コマンドオブジェクトが getEstimatedDuration() を持っていれば、プログラムは全体の処理時間を簡単に予測することができる。全てのタスクの完了がどの程度近いのかを意味のある形で示すプログレスバーを表示できる。
ウィザード 
ウィザードはあるアクションの設定のためにいくつかのページを表示し、最後のページで完了ボタンを押すまでアクションは実行されないことが多い。こうした場合、ユーザーインターフェイスのコードとアプリケーションのコードを分離するための自然な方法として、コマンドオブジェクトを用いたウィザードを作成することがある。コマンドオブジェクトはウィザードが最初に表示される際に作成される。各ウィザードのページはコマンドオブジェクト内に GUI で行われた変更を保存する。完了は、execute() を呼び出すだけである。このようにして、コマンドクラスには一切ユーザーインタフェースコードを含まないようにできる。
GUI のボタンとメニューの項目 
SwingDelphi のプログラミングでは、Action がコマンドオブジェクトである。目的のコマンドを実行する能力に加え、Action は関連するアイコンやキーボードショートカット、ツールチップのテキストなどを持つことができる。ツールバーのボタンやメニューのコンポーネントは Action オブジェクトのみを使って完全に初期化することができる。
スレッドプール 
典型的な、汎用のスレッドプールクラスは公開された addTask() メソッドを持ち、作業項目を内部の完了待ちタスクのキューに追加する。スレッドプールは、キューからコマンドを実行するスレッドのプールを維持管理する。キュー内の項目はコマンドオブジェクトである。こうしたオブジェクトは典型的に java.lang.Runnable などの共通のインターフェイスを実装しており、スレッドプールのクラス自体に特定のタスクがどのように用いられるかについて一切の情報がなくともコマンドを実行することができる。
マクロの記録
あらゆるユーザー操作がコマンドオブジェクトとして表現されていれば、コマンドオブジェクトのリストとして保持するだけ操作の流れを記録できる。その後、コマンドオブジェクトを同じ順序で実行することで、同じ操作を"再生"することができる。プログラムがスクリプトのエンジンを内蔵している場合、各コマンドオブジェクトに toScript() メソッドを実装させ、ユーザーの操作をスクリプトとして保存することができる。
ネットワーク 
コマンドオブジェクトそのものをネットワーク上に送出し、他のマシンに実行させることができる。たとえば、コンピュータゲームのプレイヤーの操作などである。
並列処理 
コマンドが共有されたリソースにタスクとして書き込まれ、多数のスレッドで並列に実行される(おそらくはリモートのマシンで—この方式はマスター/ワーカーパターンと呼ばれていることも多い)
移動可能なコード 
コードをある場所から別の場所にストリーム化・複合化できる URLClassloaders と Codebases を持つ Java などの言語を用いると、コマンドは遠隔地で搬送されるという新たな振る舞いをすることができる(EJBコマンド、マスターワーカ)。

Command パターンの構造[編集]

Command Design Pattern Class Diagram.png

関連項目[編集]