Design Pattern: Command in PHP

The next pattern from the Head First Design Patterns book is the Command Pattern. The command pattern allows decoupling of an action’s requester and the actual object that performs the action.
The command pattern can be broken down into three parts:
- invoker – is the link between commands and receiver. It also houses the receiver’s and each command as they are sent.
- command – object that encapsulates request send to receiver.
- receiver – component that is acted upon by each request
Without further ado, here’s the code from the book. If you rather play with the code, download a copy here.
interface Command{
public function execute();
public function undo();
}
class CeilingFan{
private $location;
public static $HIGH = 3;
public static $MEDIUM = 2;
public static $LOW = 1;
public static $OFF = 0;
private $speed;
public function __construct($location){
$this->location = $location;
$this->speed = self::$OFF;
}
public function high(){
print("Speed set to high");
$this->speed = self::$HIGH;
}
public function medium(){
print("Speed set to medium");
$this->speed = self::$MEDIUM;
}
public function low(){
print("Speed set to low");
$this->speed = self::$LOW;
}
public function on(){
print($this->location . " ceiling fan is turned on");
}
public function off(){
$this->speed = self::$OFF;
print($this->location . " ceiling fan is turned off");
}
public function getSpeed(){
return $this->speed;
}
}
include_once('command.php');
include_once('ceilingFan.php');
class CeilingFanHighCommand implements Command{
private $fan;
private $prevSpeed;
public function __construct(CeilingFan $fan){
$this->fan = $fan;
}
public function execute(){
$this->prevSpeed = $this->fan->getSpeed();
$this->fan->high();
}
public function undo(){
if($this->prevSpeed == CeilingFan::$HIGH){
$this->fan->high();
}
else if($this->prevSpeed == CeilingFan::$MEDIUM){
$this->fan->medium();
}
else if($this->prevSpeed == CeilingFan::$LOW){
$this->fan->low();
}
else if($this->prevSpeed == CeilingFan::$OFF){
$this->fan->off();
}
}
}
include_once('command.php');
include_once('ceilingFan.php');
class CeilingFanMediumCommand implements Command{
private $fan;
private $prevSpeed;
public function __construct(CeilingFan $fan){
$this->fan = $fan;
}
public function execute(){
$this->prevSpeed = $this->fan->getSpeed();
$this->fan->medium();
}
public function undo(){
if($this->prevSpeed == CeilingFan::$HIGH){
$this->fan->high();
}
else if($this->prevSpeed == CeilingFan::$MEDIUM){
$this->fan->medium();
}
else if($this->prevSpeed == CeilingFan::$LOW){
$this->fan->low();
}
else if($this->prevSpeed == CeilingFan::$OFF){
$this->fan->off();
}
}
}
include_once('command.php');
include_once('ceilingFan.php');
class CeilingFanLowCommand implements Command{
private $fan;
private $prevSpeed;
public function __construct(CeilingFan $fan){
$this->fan = $fan;
}
public function execute(){
$this->prevSpeed = $this->fan->getSpeed();
$this->fan->low();
}
public function undo(){
if($this->prevSpeed == CeilingFan::$HIGH){
$this->fan->high();
}
else if($this->prevSpeed == CeilingFan::$MEDIUM){
$this->fan->medium();
}
else if($this->prevSpeed == CeilingFan::$LOW){
$this->fan->low();
}
else if($this->prevSpeed == CeilingFan::$OFF){
$this->fan->off();
}
}
include_once('command.php');
include_once('ceilingFan.php');
class CeilingFanOffCommand implements Command{
private $fan;
private $prevSpeed;
public function __construct(CeilingFan $fan){
$this->fan = $fan;
}
public function execute(){
$this->prevSpeed = $this->fan->getSpeed();
$this->fan->off();
}
public function undo(){
if($this->prevSpeed == CeilingFan::$HIGH){
$this->fan->high();
}
else if($this->prevSpeed == CeilingFan::$MEDIUM){
$this->fan->medium();
}
else if($this->prevSpeed == CeilingFan::$LOW){
$this->fan->low();
}
else if($this->prevSpeed == CeilingFan::$OFF){
$this->fan->off();
}
}
}
class Light{
private $location;
public function __construct($location){
$this->location = $location;
}
public function on(){
print($this->location . " light is turned on");
}
public function off(){
print($this->location . " light is turned off");
}
}
include_once('command.php');
include_once('light.php');
class LightOffCommand implements Command{
private $light;
public function __construct(Light $light){
$this->light = $light;
}
public function execute(){
$this->light->off();
}
public function undo(){
$this->light->on();
}
}
include_once('command.php');
include_once('light.php');
class LightOnCommand implements Command{
private $light;
public function __construct(Light $light){
$this->light = $light;
}
public function execute(){
$this->light->on();
}
public function undo(){
$this->light->off();
}
}
class NoCommand {
public function __construct(){}
}
class GarageDoor {
public function __construct(){}
public function open(){
print("Garage door is opened");
}
public function close(){
print("Garage door is closed");
}
}
include_once('command.php');
include_once('garageDoor.php');
class GarageDoorCloseCommand implements Command{
private $garageDoor;
public function __construct(GarageDoor $garageDoor){
$this->garageDoor = $garageDoor;
}
public function execute(){
$this->garageDoor->close();
}
public function undo(){
$this->garageDoor->open();
}
}
include_once('command.php');
include_once('garageDoor.php');
class GarageDoorOpenCommand implements Command{
private $garageDoor;
public function __construct(GarageDoor $garageDoor){
$this->garageDoor = $garageDoor;
}
public function execute(){
$this->garageDoor->open();
}
public function undo(){
$this->garageDoor->close();
}
}
include_once("command.php");
include_once("noCommand.php");
class RemoteControl {
private $onCommands;
private $offCommands;
private $undoCommand;
public function __construct() {
$this->onCommands = array();
$this->offCommands = array();
$noCommand = new NoCommand();
for($i = 0; $i < 7; $i++){
$this->onCommands[$i] = $noCommand;
$this->offCommands[$i] = $noCommand;
}
$this->undoCommand = $noCommand;
}
public function setCommand($slot, Command $onCommand, Command $offCommand){
$this->onCommands[$slot] = $onCommand;
$this->offCommands[$slot] = $offCommand;
}
public function onButtonWasPushed($slot){
$this->onCommands[$slot]->execute();
$this->undoCommand = $this->onCommands[$slot];
}
public function offButtonWasPushed($slot){
$this->offCommands[$slot]->execute();
$this->undoCommand = $this->offCommands[$slot];
}
public function undoCommandWasPushed(){
$this->undoCommand->undo();
}
public function __toString() {
$str = "All classes tied to remote control are: <br />";
for($i = 0; $i < 7; $i++){
$str = $str . " " . get_class($this->onCommands[$i]) . " & " . get_class($this->offCommands[$i]) . "<br />";
}
return $str;
}
}
include_once('remoteControl.php');
include_once('light.php');
include_once('ceilingFan.php');
include_once('garageDoor.php');
include_once('stereo.php');
include_once('lightOnCommand.php');
include_once('lightOffCommand.php');
include_once('garageDoorOpenCommand.php');
include_once('garageDoorCloseCommand.php');
include_once('stereoOnWithCDCommand.php');
include_once('stereoOffCommand.php');
include_once('ceilingFanOnCommand.php');
include_once('ceilingFanOffCommand.php');
include_once('ceilingFanMediumCommand.php');
include_once('ceilingFanHighCommand.php');
class RemoteLoader{
public static function main(){
$remoteControl = new RemoteControl();
$livingRoomLight = new Light("Living Room");
$kitchenLight = new Light("Kitchen Light");
$ceilingFan = new CeilingFan("Living Room");
$garageDoor = new GarageDoor();
$stereo = new Stereo("Living Room");
$livingRoomLightOn = new LightOnCommand($livingRoomLight);
$livingRoomLightOff = new LightOffCommand($livingRoomLight);
$kitchenLightOn = new LightOnCommand($kitchenLight);
$kitchenLightOff = new LightOffCommand($kitchenLight);
$ceilingFanOn = new CeilingFanOnCommand($ceilingFan);
$ceilingFanOff = new CeilingFanOffCommand($ceilingFan);
$ceilingFanHighCommand = new CeilingFanHighCommand($ceilingFan);
$ceilingFanMediumCommand = new CeilingFanMediumCommand($ceilingFan);
$garageDoorOpen = new GarageDoorOpenCommand($garageDoor);
$garageDoorClose = new GarageDoorCloseCommand($garageDoor);
$stereoOnWithCD = new StereoOnWithCDCommand($stereo);
$stereoOff = new StereoOffCommand($stereo);
$remoteControl->setCommand(0, $livingRoomLightOn, $livingRoomLightOff);
$remoteControl->setCommand(1, $kitchenLightOn, $kitchenLightOff);
$remoteControl->setCommand(2, $ceilingFanOn, $ceilingFanOff);
$remoteControl->setCommand(3, $stereoOnWithCD, $stereoOff);
$remoteControl->setCommand(4, $ceilingFanHighCommand, $ceilingFanOff);
$remoteControl->setCommand(5, $ceilingFanMediumCommand, $ceilingFanOff);
print($remoteControl);
$remoteControl->onButtonWasPushed(0);
print("<br />");
$remoteControl->offButtonWasPushed(0);
print("<br />");
$remoteControl->undoCommandWasPushed();
print("<br />");
$remoteControl->onButtonWasPushed(1);
print("<br />");
$remoteControl->offButtonWasPushed(1);
print("<br />");
$remoteControl->onButtonWasPushed(2);
print("<br />");
$remoteControl->offButtonWasPushed(2);
print("<br />");
$remoteControl->undoCommandWasPushed();
print("<br />");
$remoteControl->onButtonWasPushed(3);
print("<br />");
$remoteControl->offButtonWasPushed(3);
print("<br />");
$remoteControl->onButtonWasPushed(4);
print("<br />");
$remoteControl->offButtonWasPushed(4);
print("<br />");
$remoteControl->undoCommandWasPushed();
print("<br />");
$remoteControl->onButtonWasPushed(5);
print("<br />");
$remoteControl->offButtonWasPushed(5);
print("<br />");
$remoteControl->undoCommandWasPushed();
}
}
RemoteLoader::main();
include_once('command.php');
class MacroCommand implements Command{
private $commands;
public function __construct($commands){
$this->commands = $commands;
}
public function execute(){
for($i = 0; $i < count($this->commands); $i++){
$this->commands[$i]->execute();
print("<br />");
}
}
public function undo(){
for($i = 0; $i < count($this->commands); $i++){
$this->commands[$i]->undo();
print("<br />");
}
}
}
include_once('remoteControl.php');
include_once('light.php');
include_once('ceilingFan.php');
include_once('garageDoor.php');
include_once('stereo.php');
include_once('lightOnCommand.php');
include_once('lightOffCommand.php');
include_once('stereoOnWithCDCommand.php');
include_once('stereoOffCommand.php');
include_once('macroCommand.php');
class MacroRemoteLoader{
public static function main(){
$remoteControl = new RemoteControl();
$light = new Light("Living Room");
$stereo = new Stereo("Living Room");
$lightOnCommand = new LightOnCommand($light);
$stereoOnCommand = new StereoOnWithCDCommand($stereo);
$lightOffCommand = new LightOffCommand($light);
$stereoOffCommand = new StereoOffCommand($stereo);
$partyOn = array($lightOnCommand, $stereoOnCommand);
$partyOff = array($lightOffCommand, $stereoOffCommand);
$partyOnMacro = new MacroCommand($partyOn);
$partyOffMacro = new MacroCommand($partyOff);
$remoteControl->setCommand(0, $partyOnMacro, $partyOffMacro);
$remoteControl->onButtonWasPushed(0);
$remoteControl->offButtonWasPushed(0);
}
}
MacroRemoteLoader::main();
