どうも。
最近、蒙古タンメンにハマりすぎて困っています。
麻婆麺が辛すぎて病みつきになります。
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];
}
}
制御対象が増える可能性がある時の
拡張性を考えた時に良さそうなパターンですね!


