«

»

Jun 30

Print this Post

Design patterns: command

This month I’m writting about command pattern. This is another design pattern which helps us decoupling some actions in similar way to strategy pattern. To be more specific it makes us able to encapsulate method invocation. The last word made me thinking of PHP unit tests while reading — but I’ll get back to it at the end of this post.

Book examples

Similar to strategy pattern and other patterns described in the book we face a real life problem. We’re asked to create a system to a remote controller which will be able to operate on several different devices. The offer includes a CD with driver classes to these different devices. You can download its PHP versions together with examples of code I’ve written.

However, it takes few pages to get to the clue. That’s because this time authors wants us to get familiar with a bunch of new names: client, command, invoker and reciver. These four roles are described at the begining of the chapter as particular roles in a dinnery. In this way we’re being introduced to command pattern before switch to the main task: a remote controller application. A dinnery costumer makes an order, she tells it the waitress who then passes it to the cook who creates the final product. The costumer is a client in the new terminology. The order is a command, the waitress is an invoker and the cook is a reciver. After this short introduction we can move on with implementing a command pattern in the remote controller application.

After few funny texts, ilustrations and exercies together with authors we create first command object. We start of creating a command interface which is reather simple:

#
interface Command {
    public function execute();
}

The first command object is an object with gives us a possibility to turn on a light:

#
class LightOnCommand implements Command {
    private $light;

    public function __construct(Light $light) {
        $this->light = $light;
    }

    public function execute() {
        $this->light->on();    
    }
}

Let’s create a simple class representing remote control (with only one slot and button) and its test application, so we can see how everything works:

#
class SimpleRemoteControl {
    private Command $slot;
    
    public function setCommand( $command ) {
        $this->slot = $command;        
    }

    public function buttonWasPressed() {
        $this->slot->execute();
    }
}
# 
$remote = new SimpleRemoteControl();
$light = new Light();
$lightOn = new LightOnCommand($light);
$remote->setCommand($lightOn);
$remote->buttonWasPressed();

It works. The Light::on() method simply prints on screen Light is ON message. After this simple coding we’re asked in an excercise to implement GarageDoorOpenCommand. It’s not so hard, isn’t it? After implementing it we can just switch the command in our application:

# 
$remote = new SimpleRemoteControl();

$light = new Light();
$lightOn = new LightOnCommand($light);

$garageDoor = new GarageDoor();
$garageOpen = new GarageDoorOpenCommand($garageDoor);

$remote->setCommand($lightOn);
$remote->buttonWasPressed();

$remote->setCommand($garageOpen);
$remote->buttonWasPressed();

Let’s move on, the authors finaly presents us the definition of command pattern:

The Command Pattern encapsulates a request as an object, therby letting you parameterize other objects with different requests, queue or log requests and supports undoable operations.

Command pattern diagram from Head First: Design Patterns

Command pattern diagram from Head First: Design Patterns

At this point we read about the implementation of main task. We implement six more command objects:

  • CeilingFanOnCommand,
  • StereoOnWithCdCommand,
  • LightOffCommand,
  • CeilingFanOffCommand,
  • GarageDoorClose,
  • StereoOffCommand,

We add RemoteControl class:

# 
class RemoteControl {
    const BUTTONS_NO = 7;
    private $onCommands;
    private $offComands;

    public function __construct() {
        $noCommand = new NoCommand();
        for( $i = 0; $i < = self::BUTTONS_NO; $i++ ) {
            $this->onCommands[$i] = $noCommand;
            $this->offCommands[$i] = $noCommand;
        }
    }

    public function setCommand($slotNo, $onCommand, $offCommand) {
        $this->onCommands[$slotNo] = $onCommand;
        $this->offCommands[$slotNo] = $offCommand;
    }

    public function onButtonPressed($slotNo) {
        $this->onCommands[$stotNo]->execute();
    }

    public function offButtonPressed($slotNo) {
        $this->offCommands[$stotNo]->execute();
    }

    public function __toString() {
        $result = "\n --- Remote Control -- \n";
        foreach($this->onCommands as $slotNo => $command) {
            $result .= "slot[" . $slotNo . "]" . get_class($this->onCommands[$slotNo]) . "\t" . get_class($this->offCommands[$slotNo]) . "\n";
        }

        return $result;
    }
}

And change a little bit our application code:

# 
$remoteControl = new RemoteControl();

// create all devices instances
$livingRoomLight = new Light('Living room');
$kitchenLight = new Light('Kitchen');
$ceilingFan = new CeillingFan('Living room');
$garageDoor = new GarageDoor();
$stereo = new Stereo('Living room');

// create light commands
$livingRoomLightOn = new LightOnCommand($livingRoomLight);
$livingRoomLightOff = new LightOffCommand($livingRoomLight);
$kitchenLightOn = new LightOnCommand($kitchenLight);
$kitchenLightOff = new LightOffCommand($kitchenLight);

// create ceiling commands
$ceilingFanOn = new CeillingFanOnCommand($ceilingFan);
$ceilingFanOff = new CeillingFanOffCommand($ceilingFan);

// create garage door commands
$garageDoorUp = new GarageDoorOpenCommand($garageDoor);
$garageDoorDown = new GarageDoorCloseCommand($garageDoor);

// create stereo commands
$stereoOnWithCd = new StereoOnWithCdCommand($stereo);
$stereOff = new StereoOffCommand($stereo);

// set functions of the remote control
$remoteControl->setCommand(0, $livingRoomLightOn, $livingRoomLightOff);
$remoteControl->setCommand(1, $kitchenLightOn, $kitchenLightOff);
$remoteControl->setCommand(2, $ceilingFanOn, $ceilingFanOff);
$remoteControl->setCommand(3, $stereoOnWithCd, $stereOff);

echo $remoteControl;

$remoteControl->onButtonPressed(0);
$remoteControl->offButtonPressed(0);
$remoteControl->onButtonPressed(1);
$remoteControl->offButtonPressed(1);
$remoteControl->onButtonPressed(2);
$remoteControl->offButtonPressed(2);
$remoteControl->onButtonPressed(3);
$remoteControl->offButtonPressed(3);

With this example we learned new but pretty useful null object trick. Sometimes, null object is being mentioned as a design pattern. In our example the null object instance was NoCommand class. We didn’t have a meaningfull object to assign to each slots out of the box, so we provided a NoCommand object that does nothing:

#
class NoCommand implements Command {
    public function execute() {}
}

By using this pattern we didn’t have to handle null values in RemoteControl::onButtonPressed() and RemoteControl::offButtonPressed() methods.

#
public function onButtonPressed($slotNo) {
    if( !is_null( $this->onCommands[$slotNo] ) ) {
        $this->onCommands[$stotNo]->execute();
    }
}

As a result we have a cleaner code.

This was pretty easy. The only thing left is the implementation of undo functionality. And with command pattern it comes quite easy as well: we add undo() method to our Command interface and implement it in all command classes. In example in LightOnCommand class the method looks like:

#
public function undo() {
    $this->light->off();
}

Next step is to change few things in our RemoteControl class. We add there undoCommand field, undoButtonPressed() method and add one line to both: onButtonPressed() and offButtonPressed():

# ...

public function onButtonPressed($slotNo) {
    $this->onCommands[$slotNo]->execute();
    $this->undoCommand = $this->onCommands[$slotNo];
}

public function offButtonPressed($slotNo) {
    $this->offCommands[$slotNo]->execute();
    $this->undoCommand = $this->offCommands[$slotNo];
}

public function undoButtonPressed() {
    $this->undoCommand->undo();
}

# ...

To test it we can play a little bit with our living room light and add these lines to our application code:

# 
$remoteControl->onButtonPressed(0);
$remoteControl->offButtonPressed(0);
$remoteControl->undoButtonPressed();
$remoteControl->offButtonPressed(0);
$remoteControl->undoButtonPressed();
$remoteControl->offButtonPressed(0);

And this is basically everything we were requested to implement to fulfill the requirements from the order. However, authors present us also a MacroCommand which is a specific example of using Command objects in a group and describe two more way of command pattern: queuing and logging requests.

Other examples

I didn’t find many different examples of usage of command pattern. There is one nice blog post with implementation of job queue in PHP. I like it because in the example a usage of SplQueue is presented. The showcase of JavaScript implementation of command pattern is another positive thing in the post. I also found out at least one person, Dhana Shunmugasundram, had similar idea to mine: write on a blog about design patterns described in Head First: Design patterns. It seems she stopped at command pattern. Let’s hope I’ll have more patience ;)

I mentioned at the beginning about PHPUnit. Reading about client, command, invoker and receiver, about invocation recalled in my mind names I had seen in PHPUnit package: PHP_Invoker, PHPUnit_Framework_MockObject_Invocation, PHPUnit_Framework_MockObject_Invokable and when I took a closer look into PHPUnit code it seems there are many decoupled functions. But after a while I think it’s hard to find there command pattern. I think, there are more encapsulated algorithms and more usages of strategy pattern. However, I’ve read somewhere on the Internet that command pattern is a simpler version of strategy pattern. There are also lots of usage of built-in PHP Reflection API. And I think ReflectionFunction::invoke() method is another nice example of command pattern usage: it encapsulate the invokation of reflected function/method.

Other design patterns

Here is the list of described by me design patterns:

Permanent link to this article: https://blog.lukaszewski.it/2013/06/30/design-patterns-command/

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>