One of the behavioral design patterns is the Command pattern, this pattern used to map class operations to commands (classes), so let’s see below the components of this pattern.
The command design pattern is a very common pattern in computer science, there are many examples that make use of the command pattern, for example you can think of keyboard clicks as commands, console commands, etc.
In the context of OOP the command pattern enable us to map certain class operations to commands. This enable us to decouble the invoker object from the object that implements the actual operation. Let’s imagine that you have a class calculator, this class contains common calculator operation like (Addition, Subtraction, Multiplication, Division). Now to utilize the command pattern we have to make a class (command) for each operation so we will have AddCommand, SubtractCommand, and so on.
Command Pattern Key Components
- Receiver Class: This class contains the actual operations and their implementations.
- Command Interface: This interface needs to be implemented by every concrete command class, and contains just one method execute which calls the receiver class operation.
- Concrete Commands: Those classes implement the command interface execute method, for example the AddCommand in the calculator.
- Command Invoker: This is an utility class to set commands and execute them.
Calculator Example
Let’s see the command pattern in action using calculator class. I have prepared a simple calculator class as shown below:
Calculator.php
<?php /** * Class Calculator * * this is the (Receiver) class of the command pattern, * it receives and contains the actual operations * and their implementations */ class Calculator { private $num1; private $num2; public function __construct($num1, $num2) { $this->num1 = $num1; $this->num2 = $num2; } public function add() { return $this->num1 + $this->num2; } public function subtract() { return $this->num1 - $this->num2; } public function multiply() { return $this->num1 * $this->num2; } public function divide() { return $this->num1 / $this->num2; } public function setNum1($num1) { $this->num1 = $num1; } public function setNum2($num2) { $this->num2 = $num2; } }
For demonstration purposes this is the calculator class with the four simple operations (Add, Subtract, Multiply, Divide). The next step is to map those operations into commands, but first we need a command interface.
CalculatorCommandInterface.php
<?php /** * Interface CalculatorCommandInterface * * The command interface contains just one method execute that need to be implemented * in every concrete command * */ interface CalculatorCommandInterface { public function execute(); }
At this point to make a command class we need to implement this interface, let’s see this with the AddCommand
AddCommand.php
<?php /** * Class AddCommand * * Concrete command (AddCommand) implement command interface * injects the receiver class (Calculator) to access the * real operation, in this case (add) operation * */ class AddCommand implements CalculatorCommandInterface { private $calculator; public function __construct(Calculator $calculator) { $this->calculator = $calculator; } public function execute() { return $this->calculator->add(); } }
As you see the execute() method class the receiver class add() method for this purpose we injected the receiver class into the constructor.
CommandInvoker.php
<?php /** * Class CommandInvoker * * Command invoker set commands and execute them * */ class CommandInvoker { private $command; public function __construct(CalculatorCommandInterface $command) { $this->command = $command; } public function setCommand(CalculatorCommandInterface $command) { $this->command = $command; } public function handle() { return $this->command->execute(); } }
The command invoker is like entry point to the every command class, we just set commands using the setCommand() method and execute them with the execute() method.
Let’s test this from the command line but first let’s create a client.php file
client.php
<?php require_once './autoloader.php'; $calculator = new Calculator($argv[1], $argv[2]); $invoker = new CommandInvoker(new AddCommand($calculator)); $output = $invoker->handle(); echo $output . "\n";
autoloader.php
<?php function loadClass($class) { $path = __DIR__ . '/'; require_once $path . $class .'.php'; } spl_autoload_register('loadClass');
From the command line you can run
php client.php 7 5
The client.php expects that you pass parameters from the command line, as those parameters will be available through php $argv variable. The above example will output 12
Let’s make other commands for subtract, multiply, divide
SubtractCommand.php
<?php /** * Class SubtractCommand * * Concrete command (SubtractCommand) implement command interface * */ class SubtractCommand implements CalculatorCommandInterface { private $calculator; public function __construct(Calculator $calculator) { $this->calculator = $calculator; } public function execute() { return $this->calculator->subtract(); } }
MultiplyCommand.php
<?php /** * Class MultiplyCommand * * Concrete command (MultiplyCommand) implement command interface * */ class MultiplyCommand implements CalculatorCommandInterface { private $calculator; public function __construct(Calculator $calculator) { $this->calculator = $calculator; } public function execute() { return $this->calculator->multiply(); } }
DivideCommand.php
<?php /** * Class DivideCommand * * Concrete command (DivideCommand) implement command interface * */ class DivideCommand implements CalculatorCommandInterface { private $calculator; public function __construct(Calculator $calculator) { $this->calculator = $calculator; } public function execute() { return $this->calculator->divide(); } }
client.php
<?php require_once './autoloader.php'; $operators_to_commands = [ '+' => 'AddCommand', '-' => 'SubtractCommand', 'x' => 'MultiplyCommand', '/' => 'DivideCommand' ]; if(isset($argv[3]) && isset($operators_to_commands[$argv[3]])) { $calculator = new Calculator($argv[1], $argv[2]); $invoker = new CommandInvoker(new $operators_to_commands[$argv[3]]($calculator)); $output = $invoker->handle(); echo $output . "\n"; }
Here i updated the client.php to include the operator which identifies the kind of operation and i sent this parameter in $argv[3]. For example to add two numbers:
php client.php 7 5 +
Other operations can be run also:
php client.php 7 5 - php client.php 7 5 x php client.php 7 5 /