Understanding the Command Design Pattern

Did you know there are over 4 billion mobile phones in use today? Here in Australia, we have a population of approximately 11 million people and over 22 million mobile phones – that’s an average of 2 phones per person!

It’s obvious that mobile phone usage is becoming more prevalent. And given the ubiquity of smartphones and other mobile devices, more and more customers are now opting to receive notifications via SMS rather than email. Text messages certainly have advantages over email – they’re short, immediate, and best of all SPAM is negligible.

So, what does this have to do with the Command Pattern you ask? Well, let’s look at an imaginary scenario.

A company has a website which runs a daily competition to win stuff. It has a database of over 250,000 registered users, and each user is sent a daily codeword which they must either enter or click a link in order to register their entry into the drawing. The majority of users have opted to receive an email, but a significant number are now opting to receive the notifications via SMS. Here’s the problem: How do you send a message via two different channels to both groups of users?

The logical approach would be to split the users into 2 groups, email recipients and SMS recipients, which would involve running 2 different queries and sending the codeword to each group separately. Using the Command Pattern, which I will introduce you to in this article, you can send the message to both groups of users in a single process.

Messaging Queue using the Command Pattern

The Command Pattern (also sometimes called the Action Pattern or Transaction Pattern) is a design pattern that describes how to encapsulate a request as an object so that you can queue or log clients with different requests. To demonstrate how the Command Pattern works, let’s use the simple example of a message queue. Here’s the definition of the MessageQueue class:

<?php
class MessageQueue
{
    private $queue;

    public function __construct() {
        $this->queue = array();
    }

    public function addMessage(IMessage $msg) {
        $this->queue[] = $msg;
    }

    public function execute() {
        $sendCount = 0;
        foreach ($this->queue as $msg) {
            if ($msg->send()) {
                $sendCount++;
            }
        }
        return $sendCount;
    }
}

The message queue presents two methods – an addMessage() method which adds message objects to the queue, and an execute() method which processes each message in the queue. In this example, the addMessage() method simply appends the messages to the internal array $queue, and the execute() method iterates through the elements in $queue and calls the send() method for each message object.

The Command Pattern queues each request for processing later; the actual mechanism for sending the email or SMS will be implemented in the object’s send() method. MessageQueue doesn’t need to know how to process the request as that will be the responsibility of the requesting object. To ensure the send() method is available, message objects must implement the IMessage interface.

<?php
interface IMessage
{
    public function send();
}

Each message object implements the IMessage interface and provide it’s own implementation of the send() method.

<?php
class DailyAlertEmail implements IMessage
{
...
    public function send() {
        // actual code here to send email
        // ...
        echo "Sending message via emailn";
    }
}

class DailyAlertSMS implements IMessage
{
...
    public function send() {
        // actual code here to send the SMS
        // ...
        echo "Sending message via SMSn";
    }
}

The DailyAlertEmail message implements its send() method for sending the codeword as an email, while the DailyAlertSMS message object implements its send() method for sending the message as an SMS.

Then to send both SMS and email recipients a message you would query the database for their communication preference, instantiate a suitable IMessage object and add it to the message queue, and then call the queue’s execute() method. Incidentally, creating the correct IMessage object for a user would be a good opportunity to use the Factory Method design pattern!

<?php
// create a new queue
$msgQueue = new MessageQueue();

$result = $db->query("SELECT * FROM customers");
while ($customer = $result->fetch(PDO::FETCH_ASSOC)) {
    // factory creates a DailyAlertSMS or DailyAlertEmail object
    // based on the user's preferences
    $msg = MessageFactory::build($customer, $codeword);

    // add the message object to the queue
    $msgQueue->addMessage($msg);
}

// send to all customers now
$msgQueue->execute();

Using the Command Pattern, you can retrieve all customers from the database, instantiate the appropriate IMessage implementations regardless of the customers’ communication preferences, and process them once, instead of querying the database first for all SMS customers and processing them and then repeating the process for email customers.

Keep in mind this is a basic example only; In a real world application it would be preferable to batch the SMS and email messages and send them out periodically throughout the day, ideally as a background process. With some minor modifications you can convert this to a “delayed” messaging queue run as a cron task and use the database to monitor the process’ progress.

Summary

As you can see, the Command Pattern is well suited for the following situations:

  • You want to be able to parameterize objects by an action to perform.
  • You need to specify, queue, and execute requests at different times.
  • When a set of changes to data need to be encapsulated as a single action (i.e. a transaction).

In this tutorial I’ve shown you how the Command Pattern can be a useful design pattern for implementing a command queue where requests can be queued for sequential processing, while at the same time decoupling the actual implementation of the execution from the queue itself.

Horiyan / Shutterstock

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://WebsiteURL chris

    Thanks. That’s great.
    Could you provide an example of the MessageFactory?

  • http://selflearned.com Bombero

    Thanks. Accidentally from this single example I’ve finally understood what are interfaces designed for, which I somehow couldn’t from other articles I’ve read on that subject.

  • http://www.clases-de-php.com.ar Ricardo Buquet

    Very nice article for starters
    k.i.s.s

  • http://www.anthonyw.net Anthony Wlodarski

    Interesting article. I used to do this without know the formal name for the pattern, just seemed intuitive. Good read.

  • http://www.museums-in-los-angeles.com/ Martin Hurford

    A huge mistake in the first paragraph does not inspire confidence in the level of research performed.
    Australia has 22+ million people. I have no idea how many mobile phones they have but it’s not 2 per person.

    • http://timwahrendorff.de Tim

      Nice, simple and clear. Good article.

      @Martin: I don’t know for sure about Australia, but in Germany there are 1,3 mobiles for each Person. In Sweden, there are up to 2,4 times more mobiles than people. The numbers seem correct. I would be surprised if there were less than 2 mobiles on average in Australia (the country where your neighbour is 20+ miles away).

      • http://www.richmondhillmenus.com/ Martin Hurford

        @Tim,
        You’ve never been to Australia then. More than half the population live in 5 main cities and their suburbs and believe me when I say the neighbours are not 20+ miles away.

  • http://ursdeep.wordpress.com Deep C

    Interesting article with easy to understand example … nice one !!

  • http://www.mikehealy.com.au Mike

    “Here in Australia, we have a population of approximately 11 million people”

    Um, what? Maybe in 1970 we had 11 million.

  • http://markadrake.com Mark

    This is just an article on the importance of querying a database once instead of twice. Thank you? I guess? I could write this same exact article about why you can save time if you choose to zip your pants and then button, instead of taking a break in between.

  • http://www.qtronik.com Jean-Christophe

    Nice finally Someting that talk well of the interface, implement How-to exemple! I like that! And that exemple where my next devellopement in my current project… Right on time for me to start this new way to program. Great Tanks!

  • greg

    you could have used a print example rather than the vague $msg = MessageFactory::build($customer, $codeword);
    made the post less meaningful

  • mitzip

    Wow, tough crowd. Keep up the good work Ignatius! I just saw a book on design patterns in a used bookstore and was wanting to learn more about them. Great timing!

  • John
  • http://giamsatgps.vn gps

    Nice article.
    A good example about implement interface in PHP. Thanks alot!

  • Vincent Ellis

    The articles on phpmaster are usually very good, but the recent articles by Ignatius Teo are lowering the quality bar here. His articles are just over-explained versions of WRONG examples of design patterns EXTRACTED RIGHT OUT FROM WIKIPEDIA. This guy doesn’t know anything about architecture. Jesus, have you ever read the Gang of Four book? I’m sure not, by the crap you’re writing.

  • Ignatius Teo

    @Vincent – To clarify, the articles are targeted at the beginner and intermediate level. Both the GOF and Fowler references were used in the production of this article. Any resemblance to Wikipedia is unintentional and purely coincidental.

  • http://www.originitsolution.com Web Development Company in India

    Really great things to know about PHP and its substances. Each line is useful for me. Thank you

  • sub

    Great article about Command Pattern

  • http://prinarjaya.com Oka Prinarjaya

    You say :
    …Command Pattern is well suited for the following situations:
    You need to specify, queue, and execute requests at differenttimes.

    So..i am not see any code that implementing execute request at different time

  • http://www.rodrigo-silveira.com/ Rodrigo Silveira

    So when you loop through the list of customers, are you creating a new instance of IMessage for each user? Seems like an awesome waste of memory.

    // factory creates a DailyAlertSMS or DailyAlertEmail object
    // based on the user’s preferences
    $msg = MessageFactory::build($customer, $codeword);

  • Ignatius Teo

    It’s a trivial example to illustrate the Command Pattern. You could make MessageFactory a polymorphic singleton if you like.