The Command Pattern is about wrapping a request in an object. It turns up frequently in web application frameworks, e.g. form processing where the Command Pattern is used to handle user “actions”.
First: Happy New Year. Went low tech myself and stayed well away from the keyboard, hence silence. Ton of e-mail to catch up with. Anyway, to business...
Will keep this short but hopefully sweet. The Gang of Four description of the Command Pattern’s intent is “Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.”.
An alternative way to think about the Command Pattern, from the perspective of PHP (as a language that supports both procedural and object oriented paradigms) might be “To allow multiple implementations of the same function name, each implementation being wrapped in it’s own class”. That misses many of the finer points of the Command Pattern as well as it’s intended use but helps make clear how it’s typically implemented.
Blocking
As with all things patterns, it’s easiest to see by example. Here’s a simple (and relatively useless) demo that should make things clearer.
Let’s say we want to draw some colored “blocks” in an HTML page. The number of blocks drawn and the color of each block will be defined by the end user. We’ll have a BlockRenderer class which will deal with rendering all the blocks;
class BlockRenderer { var $blocks = array(); function addBlock(& $block) { $this->blocks[] = & $block; } function render() { foreach ( $this->blocks as $key => $block ) { // foreach (in PHP4) makes copies not references to variables, // hence the $key is used, not the $block $this->blocks[$key]->draw(); } } }
The task of drawing of each block (the call to the draw() method in the above BlockRenderer class) are wrapped in seperate “Command” classes;
class RedBlock { function draw() { echo '<span style="background-color: red; padding: 10px;"></span>'; } } class BlueBlock { function draw() { echo '<span style="background-color: blue; padding: 10px;"></span>'; } } class GreenBlock { function draw() { echo '<span style="background-color: green; padding: 10px;"></span>'; } }
Now to simulate a random selection of 5 blocks, picked by a user;
$BR = & new BlockRenderer(); // An array of block class names $blocks = array('RedBlock','BlueBlock','GreenBlock'); for ($i=0;$i<=5;$i++) { // Shuffle the blocks... shuffle($blocks); // Create an instance of a block $block = & new $blocks[0]; // Add the block the the renderer $BR->addBlock($block); } // Display the blocks $BR->render();
Agreed this is a pretty useless example but the principle behind the Command Pattern is clear. We were able to have three separate implementations of the draw() “function” coexist without namespace conflicts. What’s more, it was easy easy to deal with unknown runtime conditions (an random selection of blocks), something which makes the Command Pattern useful for responding to user requests.
Command Pattern in Web Apps
Where the Command Pattern typically turns up in web applications is in frameworks like Struts: the Action class and it’s execute() method. Naming of Struts base classes is confusing though (the word “Action” is overused) so friendlier place to look is PHP‘s latest (and very nicely implemented) framework Mojavi, where the Command Pattern turns up in the Action and View classes (see docs) - the respective execute() methods.
Although web apps generally do not manifest the complexity (in terms of user interface) found is desktop apps, when it comes to form processing, the Command Pattern is particularly useful both to keep code well structured and to make handling trickier forms simple, where a user may be presented with multiple actions they can perform or where the form is a “wizard” of multiple “pages”.
Taking an example from a codebase I’m personally familiar with, consider this example. The user is presented with a choice of buttons to convert the entered text to lower of upper case. The the code for this example shows how “actions” are registered with the form processor;
$this->registerSubmitAction("upper", "ConvertToUpper");
$this->registerSubmitAction("lower", "ConvertToLower");
The first argument to the registerSubmitAction() is the value of the HTML name attribute on each button while the second argument is the name of the Action class (the Command Pattern) which deals with responding to click. Looking at the action classes themselves;
class ConvertToLower { function performAction(&$context) { $DataSpace =& $context->getDataSpace(); $DataSpace->set('Text', strtolower($DataSpace->get('Text'))); } } class ConvertToUpper { function performAction(&$context) { $DataSpace =& $context->getDataSpace(); $DataSpace->set('Text', strtoupper($DataSpace->get('Text'))); } }
Specifics aside, you’ll see that each one as the method performAction(), which is the method the form processor expects to call when responding to a request. I can register as many action classes as I like, allowing me to add further functionality to the form without intruding on the code I’ve already written. It’s also fairly easily implement a “wizard” of multiple form pages (although I’ll avoid giving you a tutorial on WACT) which might be scenario where “undo” functionality would be required.
In general, implementing “undo” is simply a matter of stepping back to the last Command executed and re-executing it. For web apps, that implies a controller which aware of state (i.e. “You’re currently on page 3 of this 5 page form”) which is fairly easy to do where forms are concerned (ala hidden input field) but typically needs cookies when you’re dealing with anything else.
As you can see, the Command Pattern is easy to grasp and implement. In many ways is simply OOP’s answer to call back functions (if that helps you think about it). Also, because “actions” are clearly identified with a class, “global” tasks such as logging and security permissions fall into place nicely around it.
Further Reading
WACT Wiki on the Command Pattern - links to further further reading... Javaworld on the Command Pattern.