Command Pattern

The pattern allows:

  • to decouple the invoker object from the handler object;
  • multi-level undo;
  • callback functionality;
  • to keep history of requests;
  • to handle requests in any time in any order.

Command Pattern


Three terms always associated with the command pattern are client, invoker and receiver. The client instantiates the command object and provides the information required to call the method at a later time. The invoker decides when the method should be called. The receiver is an instance of the class that contains the method's code.


PHP Example

The pattern is often used for job queues. The functionality, we need, can be added to the queue as jobs. Whilst the queue doesn’t need to know anything of the concrete implementation it is invoking.

<?php
/*
 * @category Design Pattern Tutorial
 * @package Command Sample
 * @author Dmitry Sheiko <me@dsheiko.com>
 * @link http://dsheiko.com
 */

/**
 * The Receiver classes
 */
abstract class Model_Abstract
{
}
class Model_Search extends Model_Abstract
{
    public function index()
    {
        echo "Site re-indexed\n";
    }
}
class Model_Session extends Model_Abstract
{
    public function cleanup()
    {
        echo "Session cleaned up\n";
    }
}
class Lib_JobQueue extends SplQueue
{
}
/**
 * The Command classes
 */
abstract class Job_Abstract
{
    protected $_receiver;
    public function  __construct(Model_Abstract $receiver) {
        $this->_receiver = $receiver;
    }
    abstract public function execute();
}
class Job_IndexSearch extends Job_Abstract
{
    public function execute()
    {
         $this->_receiver->index();
    }
}
class Job_CleanupSessions extends Job_Abstract
{
    public function execute()
    {
        $this->_receiver->cleanup();
    }
}

/**
 * Usage
 */
$queue = new SplQueue(); // Job Queue
$searchReceiver = new Model_Search();
$sessionReceiver = new Model_Session();
$queue->enqueue(new Job_IndexSearch($searchReceiver));
$queue->enqueue(new Job_CleanupSessions($sessionReceiver));

foreach ($queue as $job) {
    $job->execute();
}

// Output:
// Site re-indexed
// Session cleaned up

JS/ES5 Example

A benefit of this particular implementation of the command pattern is that the switch can be used with any end-point object: widget, window, element.

/*
 * @category Design Pattern Tutorial
 * @package Command Sample
 * @author Dmitry Sheiko <me@dsheiko.com>
 * @link http://dsheiko.com
 */
(function() {
/**
 * The invoker
 */
var SwitcherConstructor = function(showCommand, hideCommand){
    return {
        show: function() {
            showCommand.execute();
        },
        hide: function() {
            hideCommand.execute();
        }
    }
};
/**
 * The receiver
 */
var Widget = (function(){
    return {
        show : function() {
            console.log('Widget displayed');
        },
        hide : function() {
            console.log('Widget hidden');
        }
    }
}());
/**
 * The command to show given widget
 */
var showCommandConstructor = function(receiver) {
    return {
        execute: function() {
            receiver.show();
        }
    }
};
/**
 * The command to hide given widget
 */
var hideCommandConstructor = function(receiver) {
    return {
        execute: function() {
            receiver.hide();
        }
    }
};

/**
 * Usage
 */
var showCommand = new showCommandConstructor(Widget),
    hideCommand = new hideCommandConstructor(Widget),
    switcher = new SwitcherConstructor(showCommand, hideCommand);

switcher.show();
switcher.hide();

// Output:
// Widget displayed
// Widget hidden

}());