どうも。
最近、蒙古タンメンにハマりすぎて困っています。
麻婆麺が辛すぎて病みつきになります。
Commandパターン
を見ていきます。
Commandパターンの定義
リクエスト(命令)をオブジェクトとしてカプセル化し、
その結果、他のオブジェクトを異なるリクエスト、キュー
またはログリクエストなどでパラメータ化でき、
アンドゥ可能な操作もサポートする。
= リクエストをオブジェクトでカプセル化する。
= クライアントはいろんなリクエストを持つことができる。(→使える)
クラス図
縦長。。。
・Command
…全てのコマンド(オブジェクト)のためのインターフェースを定義する。
・ConcreteCommand
…Receiverとaction()の結びつきを(execute()に)定義する。
Invokerがexecute()することで
ConcreteCommandへリクエストを行い、
ConcreteCommandがReceiverの
1つ以上のaction()を呼び出すことでそれを実行する。
・Invoker
…コマンド(オブジェクト)を保持し、
ある時点でのコマンドのexecute()を呼び出すことで
コマンド(オブジェクト)にリクエストを実行するよう依頼する。
様々なコマンド(オブジェクト)をパラメタ化して保持できるが、
具体的なコマンド(オブジェクト)の内容は知らない。
(Commandインターフェースを実装している何かだと知っている程度)
・Receiver
…制御されるもの(制御対象)
・Client
具体的に…
この章でのは
「複数の電化製品のon/offを制御できるリモコン」
でした。
・Command
…制御したい命令を定義するインターフェース
・LightOnCommand / LightOffCommand [ConcreteCommand]
…具体的に制御対象であるライトの
制御(点けたり消したりする)方法がここにある
・RemoteControl [Invoker]
…制御対象(Receiver)をsetCommandで設定したり、
実際に制御するコントローラー
複数の制御対象をセットできる。
・Light [Receiver]
…制御対象となるライト
・RemoteLoader [Client]
いいところ
Invoker(RemoteControl)自体が
制御するReceiver(Light)を知っている場合、
Receiverが増えるたびに、if文で追記する形になってしまう。
RemoteControl.php
if($receiver == 'Light') { $receiver.on(); } else if($receiver == 'Door') { $receiver.open(); - } + //制御対象「Sprinkler」の追加 + } else if($receiver == 'Sprinkler') { + + $receiver.waterOn(); + + }
↓
↓ Commandパターンを使うと…
↓
Invoker(RemoteControl)は
具体的なコマンドオブジェクトの内容を知らずして
(インターフェスは知ってる)、
コマンドオブジェクトに具体的な処理(制御)を依頼できるので、
Invoker(RemoteControl)とReceiver(Light)を分離することができる。
= 各々の役割分担ができる。
RemoteControl.php
※Receiver(LightやDoorなど)について全く出てこない。
use HFD\Command\Command\Command; use HFD\Command\Command\NoCommand; class RemoteControl { /** * @var Command[] */ public $onCommands; /** * @var Command[] */ public $offCommands; public function __construct(int $commandCnt) { for ($i = 0; $i < $commandCnt; $i++) { $this->onCommands[] = new NoCommand(); $this->offCommands[] = new NoCommand(); } } public function setCommand(int $slotNum, Command $onCommand, Command $offCommand): void { $this->onCommands[$slotNum] = $onCommand; $this->offCommands[$slotNum] = $offCommand; } public function onButtonWasPushed(int $slotNum): void { $this->onCommands[$slotNum]->execute(); $this->undoCommand = $this->onCommands[$slotNum]; } public function offButtonWasPushed(int $slotNum): void { $this->offCommands[$slotNum]->execute(); $this->undoCommand = $this->offCommands[$slotNum]; } }
制御対象が増える可能性がある時の
拡張性を考えた時に良さそうなパターンですね!