Command パターンとは
動作を表現するオブジェクトを示す。Command オブジェクトは、動作とそれに伴うパラメータをカプセル化したものである。
クラスが仕事を行う時、自分のクラスや他のクラスのメソッドを呼び出す。メソッドを呼び出した結果はオブジェクトの状態に反映されるが、履歴はどこにも残らない。 こんなとき、仕事の「命令」を表現するクラスがあれば便利。行いたい仕事を「メソッドを呼び出す」という動的な処理として表現するのではなく、命令を表すクラスのインスタンスという1個の「もの」として表現することができるからである。履歴を管理したいときは、そのインスタンスの集まりを管理すればいいことになる。命令をの集まりを保存しておけば、同じ命令の再実行もできる。
デザインパターンではこのような「命令」にCommandパターンという名前をつけている。CommandはEventと呼ばれる場合もある。
example
サンプルコードとして、wikiのJavaサンプルコードを引用する。
Consider a “simple” switch. In this example we configure the Switch with two commands: to turn the light on and to turn the light off. A benefit of this particular implementation of the command pattern is that the switch can be used with any device, not just a light. The Switch in the following C# implementation turns a light on and off, but the Switch’s constructor is able to accept any subclasses of Command for its two parameters. For example, you could configure the Switch to start an engine.
Commandインターフェース
<?php interface Command { public function execute(); public function __toString(): string; }
MySwitchクラス
<?php class MySwitch { private $history = []; public function storeAndExecute(Command $cmd) { $this->history[] = $cmd; $cmd->execute(); } public function displayHistory() { foreach($this->history as $k => $v) { echo "{$k}: {$v}" . PHP_EOL; } } }
Lightクラス
<?php class Light { public function turnOn() { echo "The light is on" . PHP_EOL; } public function turnOff() { echo "The light is off" . PHP_EOL; } }
FlipUpCommandクラス
<?php class FlipUpCommand implements Command { private $theLight; public function FlipUpCommand(Light $light) { $this->theLight = $light; } public function execute() { $this->theLight->turnOn(); } public function __toString() : string { return get_class($this); } }
FlipDownCommandクラス
<?php class FlipDownCommand implements Command { private $theLight; public function FlipDownCommand(Light $light) { $this->theLight = $light; } public function execute() { $this->theLight->turnOff(); } public function __toString(): string { return get_class($this); } }
Main
<?php $lamp = new Light(); $switchUp = new FlipUpCommand($lamp); $switchDown = new FlipDownCommand($lamp); $mySwitch = new MySwitch(); for($i = 0; $i < 10; $i++) { if (boolval(rand(0, 1))) { $mySwitch->storeAndExecute($switchUp); } else { $mySwitch->storeAndExecute($switchDown); } usleep(50000); // wait 0.5 sec } echo PHP_EOL . "=== command history ===" . PHP_EOL; $mySwitch->displayHistory();
実行結果
$ php Main.php The light is on The light is off The light is off The light is off The light is off The light is off The light is on The light is on The light is off The light is off === command history === 0: FlipUpCommand 1: FlipDownCommand 2: FlipDownCommand 3: FlipDownCommand 4: FlipDownCommand 5: FlipDownCommand 6: FlipUpCommand 7: FlipUpCommand 8: FlipDownCommand 9: FlipDownCommand
ソースコード
役割
Command役
命令のインターフェースを定義する役。 サンプルコードにおけるCommandインターフェース。
ConcreteCommand役
Command役のインターフェースを実装している役。 サンプルコードにおけるFlipUpCommandクラス、FlipDownCommandクラス。
Receiver役
Command役が命令を実行するときに対象となる役。命令の受け取り手とも呼べる。 サンプルコードにおけるLightクラス。
Client役
ConcreteCommand役を生成し、その際にReceiver役を割り当てる役。 サンプルコードにおけるMain.php。
Invoker役
命令の実行を開始する役。Command役で定義されているインターフェースを呼び出す役となる。 サンプルコードにおけるMySwitchクラス。
まとめ
「命令」をオブジェクトとして表現することで、履歴をとったり再実行を行ったりすることが可能となる。
関連パターン
- PHP7でデザインパターン入門11/23 Compositeパターン - Do Something
- PHP7でデザインパターン入門18/23 Mementoパターン - Do Something
- PHP7でデザインパターン入門6/23 Prototypeパターン - Do Something
- 作者: 結城浩
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2004/06/19
- メディア: 大型本
- 購入: 51人 クリック: 762回
- この商品を含むブログ (399件) を見る