PHP Design Patterns
After covering a few creational and structural design patterns, we have started behavioral patterns now. You can see the first article in this category of the strategy pattern. With creational patterns, we learned how we should create our objects, and from structural patterns we learned how we should structure our classes and objects to help build a better application.
In this article, we will be going through the command design pattern. As the name says, in this pattern we will be dealing with executing various commands. Let me take a word about this pattern from Wikipedia:
The command pattern is a behavioral design pattern in which an object is used to represent and encapsulate all the information needed to call a method at a later time. This information includes the method name, the object that owns the method and values for the method parameters.
Basically a pattern has numerous elements involved, which are as below. In the next section, we will be exploring each element with a code example. I will be taking the example of radio actions—very basic actions would be turning the radio on or off. So let's dive into each element.
Receiver
This element contains the actual implementation (knows how to carry out requested command) of any commands. This also maintains the history of executed commands, but it is not part of the actual command pattern. We will see that part in the Memento Design Pattern.
// Receiver
class
radioControl {
public
function
turnOn() {
// Turning On Radio
echo
"Turning On Radio"
;
}
public
function
turnOff() {
// Turning Off Radio
echo
"Turning Off Radio"
;
}
}
// Receiver
class
radioControl {
public
function
turnOn() {
// Turning On Radio
echo
"Turning On Radio"
;
}
public
function
turnOff() {
// Turning Off Radio
echo
"Turning Off Radio"
;
}
}
Command
This element contains information about the necessary action to be taken. It calls the required method from
receiver
.
// Command
interface
radioCommand {
public
function
execute();
}
class
turnOnRadio
implements
radioCommand {
private
$radioControl
;
public
function
__construct(radioControl
$radioControl
) {
$this
->radioControl =
$radioControl
;
}
public
function
execute() {
$this
->radioControl->turnOn ();
}
}
class
turnOffRadio
implements
radioCommand {
private
$radioControl
;
public
function
__construct(radioControl
$radioControl
) {
$this
->radioControl =
$radioControl
;
}
public
function
execute() {
$this
->radioControl->turnOff ();
}
}
// Command
interface
radioCommand {
public
function
execute();
}
class
turnOnRadio
implements
radioCommand {
private
$radioControl
;
public
function
__construct(radioControl
$radioControl
) {
$this
->radioControl =
$radioControl
;
}
public
function
execute() {
$this
->radioControl->turnOn ();
}
}
class
turnOffRadio
implements
radioCommand {
private
$radioControl
;
public
function
__construct(radioControl
$radioControl
) {
$this
->radioControl =
$radioControl
;
}
public
function
execute() {
$this
->radioControl->turnOff ();
}
}
Client
This element really behaves like a client (deciding what to do). Its job is to determine which command to execute, without knowing who will execute it and how it will be executed. In this example I have taken command as a hard-coded value, but it can be grabbed from anywhere like a value from a URL and/or post variable as well.
// Client
$in
=
'turnOffRadio'
;
Invoker
This element initiates the whole process. It takes arguments from the client and invokes the process to call the required command.
// Invoker
if
(
class_exists
(
$in
)) {
$command
=
new
$in
(
new
radioControl () );
}
else
{
throw
new
Exception (
'..Command Not Found..'
);
}
$command
->execute ();
Once we execute this command it will show "Turning Off Radio" as an output, because the client has invoked that command. Additional commands can be executed in the same way. If our action was set as
turnOffRadio
, then it should show "Turning On Radio". Simple enough, isn't it?Putting It All Together
Let's wrap up all the elements here to see how it works.
// Receiver
class
radioControl {
public
function
turnOn() {
// Turning On Radio
echo
"Turning On Radio"
;
}
public
function
turnOff() {
// Turning Off Radio
echo
"Turning Off Radio"
;
}
}
// Command
interface
radioCommand {
public
function
execute();
}
class
turnOnRadio
implements
radioCommand {
private
$radioControl
;
public
function
__construct(radioControl
$radioControl
) {
$this
->radioControl =
$radioControl
;
}
public
function
execute() {
$this
->radioControl->turnOn ();
}
}
class
turnOffRadio
implements
radioCommand {
private
$radioControl
;
public
function
__construct(radioControl
$radioControl
) {
$this
->radioControl =
$radioControl
;
}
public
function
execute() {
$this
->radioControl->turnOff ();
}
}
// Client
$in
=
'turnOffRadio'
;
// Invoker
if
(
class_exists
(
$in
)) {
$command
=
new
$in
(
new
radioControl () );
}
else
{
throw
new
Exception (
'..Command Not Found..'
);
}
$command
->execute ();
Adding New Commands
Earlier we had only one frequency to play on the radio, so we had only two methods, which are to turn On or Off radio. But imagine that as time goes we have multiple frequencies to play, forcing us to add two new methods:
tuneUp
and tuneDown
. Let's see how we can add those.
When we use design patterns, it enables us to make changes or extend functionality without making any changes in the client code. This applies here as well. We are going to add two more commands, but our client and invoker code will remain as they are.
Adding new commands requires changes in two places. The first is to create new commands which implement our
radioCommand
interface, and next is to define the actual implementation of those commands in the receiver.New Commands
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
| class tuneUpRadio implements radioCommand { private $radioControl ; public function __construct(radioControl $radioControl ) { $this ->radioControl = $radioControl ; } public function execute() { $this ->radioControl->tuneUp (); } } class tuneDownRadio implements radioCommand { private $radioControl ; public function __construct(radioControl $radioControl ) { $this ->radioControl = $radioControl ; } public function execute() { $this ->radioControl->tuneDown (); } } |
Updated Receiver Code
We will be adding two new methods in our receiver class.
// Receiver
class
radioControl {
public
function
turnOn() {
// Turning On Radio
echo
"Turning On Radio"
;
}
public
function
turnOff() {
// Turning Off Radio
echo
"Turning Off Radio"
;
}
public
function
tuneUp() {
// Tuning Up Radio
echo
"Tuning Up Radio"
;
}
public
function
tuneDown() {
// Tuning Down Radio
echo
"Tuning Down Radio"
;
}
}
Conclusion
So we should go with the Command design pattern when we have multiple commands to execute, and it does not matter if those commands are related to each other or not. I have tried my best to elaborate on this design pattern, and you can post your feedback in the comment section.
0 comments :