Thursday, February 11, 2010

Practical Php Patterns: Command

This post is the second one in the behavioral patterns part of the Practical Php Pattern series.

The behavioral pattern we will discuss today is the Command one, a mechanism for encapsulation of a generic operation.
If you are familiar with C or Php, you have probably already encountered Command as its procedural equivalent: the callback, which is usually implemented as a function pointer or a data structure such as a string or an array in php.
Command is an abstraction over a method call, which becomes a first-class object with all the benefits of object orientation over a set of routines: composition, inheritance and handling.
For example, the GoF book proposes to use Commands to store a chain of user actions and supporting undoing and redoing operations.
Note that php 5.3 functional programming capabilities (Closures) can be used as a native implementation of the Command pattern. Though, there is an advantage in type safety in using an abstract data type for every Command hierarchy.

In this pattern, the Invoker knows that a Command is passed to it, without dependencies on the actual ConcreteCommand implementation. The solved problem is the association of method calls by configuration: for instance ui controls like buttons and menus refer to a Command and assume their behavior by composing a generic ConcreteCommand instance.

Participants:
  • Command: defines an abstraction over a method call.
  • ConcreteCommand: implementation of an operation.
  • Invoker: refers to Command instances as its available operations.
The code sample provides Validator components implemented as Command objects.
<?php
/**
 * The Command abstraction.
 * In this case the implementation must return a result,
 * sometimes it only has side effects.
 */
interface Validator
{
    /**
     * The method could have any parameters.
     * @param mixed
     * @return boolean
     */
    public function isValid($value);
}

/**
 * ConcreteCommand.
 */
class MoreThanZeroValidator implements Validator
{
    public function isValid($value)
    {
        return $value > 0;
    }
}

/**
 * ConcreteCommand.
 */
class EvenValidator implements Validator
{
    public function isValid($value)
    {
        return $value % 2 == 0;
    }
}

/**
 * The Invoker. An implementation could store more than one
 * Validator if needed.
 */
class ArrayProcessor
{
    protected $_rule;

    public function __construct (Validator $rule)
    {
        $this->_rule = $rule;
    }

    public function process(array $numbers)
    {
        foreach ($numbers as $n) {
            if ($this->_rule->IsValid($n)) {
                echo $n, "\n";
            }
        }
    }
}

// Client code
$processor = new ArrayProcessor(new EvenValidator());
$processor->process(array(1, 20, 18, 5, 0, 31, 42));
Some implementation notes for this pattern:
  • some of the parameters for the method call can be provided at the construction of the ConcreteCommand, effectively currying the original method.
  • A Command can be considered as a very simple Strategy, with only one method, and the emphasis put on the operation as an object you can pass around.
  • ConcreteCommands also compose every resource they need to achieve their goal, primarily the Receiver of the action where they call method to execute a Command.
  • Composite, Decorator and other patterns can be mixed with the Command one, obtaining multiple Commands, decorated Commands and so on.

No comments:

Post a Comment