Command パターン | デザインパターン
2022年9年23日
デザインパターン
Command
PHP
オライリージャパンによる Head First シリーズ デザインパターン(第2版)第6章 Command パターンを、 PHPで書き直してみようという試みです。
Light.php
namespace Command; class Light { public string $name; public function __construct(string $name) { $this->name = $name; } public function on() : void { echo $this->name . ' 照明が点いています'; echo "\n"; } public function off() : void { echo $this->name . ' 照明が消えています'; echo "\n"; } }
CeilingFan.php
namespace Command; class CeilingFan { public string $name; public function __construct(string $name) { $this->name = $name; } public function on() : void { echo $this->name . ' シーリングファンの強さは「強」です'; echo "\n"; } public function off() : void { echo $this->name . ' シーリングファンは止まっています'; echo "\n"; } }
Stereo.php
namespace Command; class Stereo { public string $name; public function __construct(string $name) { $this->name = $name; } public function on() : void { echo $this->name . ' オーディオの電源が入っています'; echo "\n"; } public function off() : void { echo $this->name . ' オーディオの電源は切れています'; echo "\n"; } public function setCD() : void { echo $this->name . ' オーディオがCD入力に設定されています'; echo "\n"; } public function setVolume(int $volume) : void { echo $this->name . ' オーディオのボリュームが' . strval($volume) . 'に設定されています'; echo "\n"; } }
Command.php
namespace Command; interface Command { public function execute() : void; }
NoCommand.php
namespace Command; class NoCommand implements Command { public function execute() : void { echo 'NoCommand'; echo "\n"; } public function undo() : void { echo 'NoCommand'; echo "\n"; } }
LightOnCommand.php
namespace Command; class LightOnCommand implements Command { public Light $light; public function __construct(Light $light) { $this->light = $light; } public function execute() : void { $this->light->on(); } }
LightOffCommand.php
namespace Command; class LightOffCommand implements Command { public Light $light; public function __construct(Light $light) { $this->light = $light; } public function execute() : void { $this->light->off(); } }
CeilingFanOnCommand.php
namespace Command; class CeilingFanOnCommand implements Command { public CeilingFan $ceilingFan; public function __construct(CeilingFan $ceilingFan) { $this->ceilingFan = $ceilingFan; } public function execute() : void { $this->ceilingFan->on(); } }
CeilingFanOffCommand.php
namespace Command; class CeilingFanOffCommand implements Command { public CeilingFan $ceilingFan; public function __construct(CeilingFan $ceilingFan) { $this->ceilingFan = $ceilingFan; } public function execute() : void { $this->ceilingFan->off(); } }
StereoOnWithCDCommand.php
namespace Command; class StereoOnWithCDCommand implements Command { public Stereo $stereo; public function __construct(Stereo $stereo) { $this->stereo = $stereo; } public function execute() : void { $this->stereo->on(); $this->stereo->setCD(); $this->stereo->setVolume(11); } }
StereoOffCommand.php
namespace Command; class StereoOffCommand implements Command { public Stereo $stereo; public function __construct(Stereo $stereo) { $this->stereo = $stereo; } public function execute() : void { $this->stereo->off(); } }
StereoOffCommand.php
namespace Command; class RemoteControl { public array $onCommand; public array $offCommand; public function __construct(){ $this->onCommand = []; $this->offCommand = []; $noCommand = New NoCommand(); $this->onCommand = array_pad($this->onCommand, 7, $noCommand); $this->offCommand = array_pad($this->offCommand, 7, $noCommand); } public function setCommand(int $slot, Command $onCommand, Command $offCommand) : void { $this->onCommand[$slot] = $onCommand; $this->offCommand[$slot] = $offCommand; } public function onButtonWasPushed(int $slot) : void { $this->onCommand[$slot]->execute(); } public function offButtonWasPushed(int $slot) : void { $this->offCommand[$slot]->execute(); } public function toString() : string { $stringBuf = null; for ($i = 0; $i < count($this->onCommand); $i++) { $onCommandClassName = str_replace(__NAMESPACE__ . '\\', '', get_class($this->onCommand[$i])); $offCommandClassName = str_replace(__NAMESPACE__ . '\\', '', get_class($this->offCommand[$i])); $stringBuf .= '[スロット' . $i . ']' . ' ' . $onCommandClassName . ' ' . $offCommandClassName . "\n"; } return $stringBuf; } }
index.php
use Command\Light; use Command\LightOnCommand; use Command\LightOffCommand; use Command\CeilingFan; use Command\CeilingFanOnCommand; use Command\CeilingFanOffCommand; use Command\Stereo; use Command\StereoOnWithCDCommand; use Command\StereoOffCommand; use Command\RemoteControl; $livingRoomLight = new Light('リビングルーム'); $livingRoomLightOn = new LightOnCommand($livingRoomLight); $livingRoomLightOff = new LightOffCommand($livingRoomLight); $kitchenLight = new Light('キッチン'); $kitchenLightOn = new LightOnCommand($kitchenLight); $kitchenLightOff = new LightOffCommand($kitchenLight); $ceilingFan = new CeilingFan('リビングルーム'); $ceilingFanOn = new CeilingFanOnCommand($ceilingFan); $ceilingFanOff = new CeilingFanOffCommand($ceilingFan); $stereo = new Stereo('リビングルーム'); $stereoOn = new StereoOnWithCDCommand($stereo); $stereoOff = new StereoOffCommand($stereo); $remoteControl = new RemoteControl(); $remoteControl->setCommand(0, $livingRoomLightOn, $livingRoomLightOff); $remoteControl->setCommand(1, $kitchenLightOn, $kitchenLightOff); $remoteControl->setCommand(2, $ceilingFanOn, $ceilingFanOff); $remoteControl->setCommand(3, $stereoOn, $stereoOff); echo $remoteControl->toString(); $remoteControl->onButtonWasPushed(0); $remoteControl->offButtonWasPushed(0); $remoteControl->onButtonWasPushed(1); $remoteControl->offButtonWasPushed(1); $remoteControl->onButtonWasPushed(2); $remoteControl->offButtonWasPushed(2); $remoteControl->onButtonWasPushed(3); $remoteControl->offButtonWasPushed(3);
出力結果
[スロット0] LightOnCommand LightOffCommand [スロット1] LightOnCommand LightOffCommand [スロット2] CeilingFanOnCommand CeilingFanOffCommand [スロット3] StereoOnWithCDCommand StereoOffCommand [スロット4] NoCommand NoCommand [スロット5] NoCommand NoCommand [スロット6] NoCommand NoCommand リビングルーム 照明が点いています リビングルーム 照明が消えています キッチン 照明が点いています キッチン 照明が消えています リビングルーム シーリングファンの強さは「強」です リビングルーム シーリングファンは止まっています リビングルーム オーディオの電源が入っています リビングルーム オーディオがCD入力に設定されています リビングルーム オーディオのボリュームが11に設定されています リビングルーム オーディオの電源は切れています
LightOnCommand.php
namespace Command; class LightOnCommand implements Command { public Light $light; public function __construct(Light $light) { $this->light = $light; } public function execute() : void { $this->light->on(); } public function undo() : void { $this->light->off(); } }
LightOffCommand.php
namespace Command; class LightOffCommand implements Command { public Light $light; public function __construct(Light $light) { $this->light = $light; } public function execute() : void { $this->light->off(); } public function undo() : void { $this->light->on(); } }
RemoteControlWithUndo.php
namespace Command; class RemoteControlWithUndo { public array $onCommand; public array $offCommand; public $undoCommand; public function __construct(){ $this->onCommand = []; $this->offCommand = []; $noCommand = New NoCommand(); $this->onCommand = array_pad($this->onCommand, 7, $noCommand); $this->offCommand = array_pad($this->offCommand, 7, $noCommand); $this->undoCommand = $noCommand; } public function setCommand(int $slot, Command $onCommand, Command $offCommand) : void { $this->onCommand[$slot] = $onCommand; $this->offCommand[$slot] = $offCommand; } public function onButtonWasPushed(int $slot) : void { $this->onCommand[$slot]->execute(); $this->undoCommand = $this->onCommand[$slot]; } public function offButtonWasPushed(int $slot) : void { $this->offCommand[$slot]->execute(); $this->undoCommand = $this->offCommand[$slot]; } public function undoButtonWasPushed(int $slot) : void { $this->undoCommand->undo(); } public function toString() : string { $stringBuf = null; for ($i = 0; $i < count($this->onCommand); $i++) { $onCommandClassName = str_replace(__NAMESPACE__ . '\\', '', get_class($this->onCommand[$i])); $offCommandClassName = str_replace(__NAMESPACE__ . '\\', '', get_class($this->offCommand[$i])); $stringBuf .= '[スロット' . $i . ']' . ' ' . $onCommandClassName . ' ' . $offCommandClassName . "\n"; } $undoCommand = str_replace(__NAMESPACE__ . '\\', '', get_class($this->undoCommand)); $stringBuf .= '[アンドゥ]' . ' ' . $undoCommand . "\n"; return $stringBuf; } }
index.php
use Command\Light; use Command\LightOnCommand; use Command\LightOffCommand; use Command\RemoteControlWithUndo; $livingRoomLight = new Light('リビングルーム'); $livingRoomLightOn = new LightOnCommand($livingRoomLight); $livingRoomLightOff = new LightOffCommand($livingRoomLight); $remoteControl = new RemoteControlWithUndo(); $remoteControl->setCommand(0, $livingRoomLightOn, $livingRoomLightOff); $remoteControl->onButtonWasPushed(0); $remoteControl->offButtonWasPushed(0); echo $remoteControl->toString(); $remoteControl->undoButtonWasPushed(0); $remoteControl->offButtonWasPushed(0); $remoteControl->onButtonWasPushed(0); echo $remoteControl->toString(); $remoteControl->undoButtonWasPushed(0);
出力結果
リビングルーム 照明が点いています リビングルーム 照明が消えています [スロット0] LightOnCommand LightOffCommand [スロット1] LightOnCommand LightOffCommand [スロット2] CeilingFanOnCommand CeilingFanOffCommand [スロット3] StereoOnWithCDCommand StereoOffCommand [スロット4] NoCommand NoCommand [スロット5] NoCommand NoCommand [スロット6] NoCommand NoCommand [アンドゥ] LightOffCommand リビングルーム 照明が点いています リビングルーム 照明が消えています リビングルーム 照明が点いています [スロット0] LightOnCommand LightOffCommand [スロット1] LightOnCommand LightOffCommand [スロット2] CeilingFanOnCommand CeilingFanOffCommand [スロット3] StereoOnWithCDCommand StereoOffCommand [スロット4] NoCommand NoCommand [スロット5] NoCommand NoCommand [スロット6] NoCommand NoCommand [アンドゥ] LightOnCommand リビングルーム 照明が消えています
CeilingFan.php
namespace Command; class CeilingFan { public int $HIGH = 3; public int $MEDIUM = 2; public int $LOW = 1; public int $OFF = 0; public string $name; public int $speed = 0; public function __construct(string $name) { $this->name = $name; } public function on() : void { $this->speed = $this->HIGH; echo $this->name . 'シーリングファンの強さは「強」です'; echo "\n"; } public function high() : void { $this->speed = $this->HIGH; echo $this->name . 'シーリングファンの強さは「強」です'; echo "\n"; } public function medium() : void { $this->speed = $this->MEDIUM; echo $this->name . 'シーリングファンの強さは「中」です'; echo "\n"; } public function low() : void { $this->speed = $this->LOW; echo $this->name . 'シーリングファンの強さは「弱」です'; echo "\n"; } public function off() : void { $this->speed = $this->OFF; echo $this->name . 'シーリングファンが止まっています'; echo "\n"; } public function getSpeed() : int { return $this->speed; } }
CeilingFanHighCommand.php
namespace Command; class CeilingFanHighCommand implements Command { public CeilingFan $ceilingFan; public int $prevSpeed; public function __construct(CeilingFan $ceilingFan) { $this->ceilingFan = $ceilingFan; } public function execute() : void { $this->prevSpeed = $this->ceilingFan->getSpeed(); $this->ceilingFan->high(); } public function undo() : void { if ($this->prevSpeed == $this->ceilingFan->HIGH) { $this->ceilingFan->high(); } else if ($this->prevSpeed == $this->ceilingFan->MEDIUM) { $this->ceilingFan->medium(); } else if ($this->prevSpeed == $this->ceilingFan->LOW) { $this->ceilingFan->low(); } else if ($this->prevSpeed == $this->ceilingFan->OFF) { $this->ceilingFan->high(); } } }
CeilingFanMediumCommand.php
namespace Command; class CeilingFanMediumCommand implements Command { public CeilingFan $ceilingFan; public int $prevSpeed; public function __construct(CeilingFan $ceilingFan) { $this->ceilingFan = $ceilingFan; } public function execute() : void { $this->prevSpeed = $this->ceilingFan->getSpeed(); $this->ceilingFan->medium(); } public function undo() : void { if ($this->prevSpeed == $this->ceilingFan->HIGH) { $this->ceilingFan->high(); } else if ($this->prevSpeed == $this->ceilingFan->MEDIUM) { $this->ceilingFan->medium(); } else if ($this->prevSpeed == $this->ceilingFan->LOW) { $this->ceilingFan->low(); } else if ($this->prevSpeed == $this->ceilingFan->OFF) { $this->ceilingFan->high(); } } }
CeilingFanLowCommand.php
namespace Command; class CeilingFanLowCommand implements Command { public CeilingFan $ceilingFan; public int $prevSpeed; public function __construct(CeilingFan $ceilingFan) { $this->ceilingFan = $ceilingFan; } public function execute() : void { $this->prevSpeed = $this->ceilingFan->getSpeed(); $this->ceilingFan->low(); } public function undo() : void { if ($this->prevSpeed == $this->ceilingFan->HIGH) { $this->ceilingFan->high(); } else if ($this->prevSpeed == $this->ceilingFan->MEDIUM) { $this->ceilingFan->medium(); } else if ($this->prevSpeed == $this->ceilingFan->LOW) { $this->ceilingFan->low(); } else if ($this->prevSpeed == $this->ceilingFan->OFF) { $this->ceilingFan->high(); } } }
CeilingFanOffCommand.php
namespace Command; class CeilingFanOffCommand implements Command { public CeilingFan $ceilingFan; public int $prevSpeed; public function __construct(CeilingFan $ceilingFan) { $this->ceilingFan = $ceilingFan; } public function execute() : void { $this->prevSpeed = $this->ceilingFan->getSpeed(); $this->ceilingFan->off(); } public function undo() : void { if ($this->prevSpeed == $this->ceilingFan->HIGH) { $this->ceilingFan->high(); } else if ($this->prevSpeed == $this->ceilingFan->MEDIUM) { $this->ceilingFan->medium(); } else if ($this->prevSpeed == $this->ceilingFan->LOW) { $this->ceilingFan->low(); } else if ($this->prevSpeed == $this->ceilingFan->OFF) { $this->ceilingFan->high(); } } }
index.php
use Command\CeilingFan; use Command\CeilingFanHighCommand; use Command\CeilingFanMediumCommand; use Command\CeilingFanLowCommand; use Command\CeilingFanOffCommand; use Command\RemoteControlWithUndo; $ceilingFan = new CeilingFan('リビングルーム'); $ceilingFanHigh = new CeilingFanHighCommand($ceilingFan); $ceilingFanMedium = new CeilingFanMediumCommand($ceilingFan); $ceilingFanOff = new CeilingFanOffCommand($ceilingFan); $remoteControl = new RemoteControlWithUndo(); $remoteControl->setCommand(0, $ceilingFanMedium, $ceilingFanOff); $remoteControl->setCommand(1, $ceilingFanHigh, $ceilingFanOff); $remoteControl->onButtonWasPushed(0); $remoteControl->offButtonWasPushed(0); echo $remoteControl->toString(); $remoteControl->undoButtonWasPushed(0); $remoteControl->onButtonWasPushed(1); echo $remoteControl->toString(); $remoteControl->undoButtonWasPushed(1);
出力結果
リビングルームシーリングファンの強さは「中」です リビングルームシーリングファンが止まっています [スロット0] CeilingFanMediumCommand CeilingFanOffCommand [スロット1] CeilingFanHighCommand CeilingFanOffCommand [スロット2] NoCommand NoCommand [スロット3] NoCommand NoCommand [スロット4] NoCommand NoCommand [スロット5] NoCommand NoCommand [スロット6] NoCommand NoCommand [アンドゥ] CeilingFanOffCommand リビングルームシーリングファンの強さは「中」です リビングルームシーリングファンの強さは「強」です [スロット0] CeilingFanMediumCommand CeilingFanOffCommand [スロット1] CeilingFanHighCommand CeilingFanOffCommand [スロット2] NoCommand NoCommand [スロット3] NoCommand NoCommand [スロット4] NoCommand NoCommand [スロット5] NoCommand NoCommand [スロット6] NoCommand NoCommand [アンドゥ] CeilingFanHighCommand リビングルームシーリングファンの強さは「中」です
MacroCommand.php
namespace Command; class MacroCommand implements Command { public array $commands = []; public function __construct(array $commands) { $this->commands = $commands; } public function execute() : void { for($i = 0; $i < count($this->commands); $i++){ $this->commands[$i]->execute(); } } public function undo() : void { } }
TV.php
namespace Command; class TV { public string $name; public function __construct(string $name) { $this->name = $name; } public function on() : void { echo $this->name . ' TVの電源が入っています'; echo "\n"; } public function off() : void { echo $this->name . ' TVの電源が切れています'; echo "\n"; } public function setDVD() : void { echo $this->name . ' TVのチャンネルがDVDに設定されています'; echo "\n"; } }
TVOnCommand.php
namespace Command; class TVOnCommand implements Command { public TV $tv; public function __construct(TV $tv) { $this->tv = $tv; } public function execute() : void { $this->tv->on(); $this->tv->setDVD(); } public function undo() : void { $this->tv->off(); } }
TVOffCommand.php
namespace Command; class TVOffCommand implements Command { public TV $tv; public function __construct(TV $tv) { $this->tv = $tv; } public function execute() : void { $this->tv->off(); } public function undo() : void { $this->tv->on(); } }
Hottub.php
namespace Command; class Hottub { public function __construct() { } public function on() : void { echo '風呂が40度まで熱くなっています'; echo "\n"; echo 'バブルバスが動いています!'; echo "\n"; } public function off() : void { echo '風呂が37度まで冷めています'; echo "\n"; } }
HottubOnCommand.php
namespace Command; class HottubOnCommand implements Command { public Hottub $hottub; public function __construct(Hottub $hottub) { $this->hottub = $hottub; } public function execute() : void { $this->hottub->on(); } public function undo() : void { $this->hottub->off(); } }
HottubOffCommand.php
namespace Command; class HottubOffCommand implements Command { public Hottub $hottub; public function __construct(Hottub $hottub) { $this->hottub = $hottub; } public function execute() : void { $this->hottub->off(); } public function undo() : void { $this->hottub->on(); } }
HottubOffCommand.php
$light = new Light('リビングルーム'); $stereo = new Stereo('リビングルーム'); $tv = new TV('リビングルーム'); $hottub = new Hottub(); $lightOn = new LightOnCommand($light); $stereoOn = new StereoOnCommand($stereo); $tvOn = new TVOnCommand($tv); $hottubOn = new HottubOnCommand($hottub); $lightOff = new LightOffCommand($light); $stereoOff = new StereoOffCommand($stereo); $tvOff = new TVOffCommand($tv); $hottubOff = new HottubOffCommand($hottub); $partyOn = [$lightOn,$stereoOn,$tvOn,$hottubOn]; $partyOff = [$lightOff,$stereoOff,$tvOff,$hottubOff]; $partyOnMacro = new MacroCommand($partyOn); $partyOffMacro = new MacroCommand($partyOff); $remoteControl = new RemoteControlWithUndo(); $remoteControl->setCommand(0, $partyOnMacro, $partyOffMacro); echo $remoteControl->toString(); echo '--- マクロのOnを押す ---' . "\n"; $remoteControl->onButtonWasPushed(0); echo '--- マクロのOffを押す ---' . "\n"; $remoteControl->offButtonWasPushed(0);
出力結果
[スロット0] MacroCommand MacroCommand [スロット1] NoCommand NoCommand [スロット2] NoCommand NoCommand [スロット3] NoCommand NoCommand [スロット4] NoCommand NoCommand [スロット5] NoCommand NoCommand [スロット6] NoCommand NoCommand [アンドゥ] NoCommand --- マクロのOnを押す --- リビングルーム 照明が点いています リビングルーム オーディオの電源が入っています リビングルーム TVの電源が入っています リビングルーム TVのチャンネルがDVDに設定されています 風呂が40度まで熱くなっています バブルバスが動いています! --- マクロのOffを押す --- リビングルーム 照明が消えています リビングルーム オーディオの電源は切れています リビングルーム TVの電源が切れています 風呂が37度まで冷めています