Disciplined Agile

The Command Pattern

Contents


The Command Pattern


The Command Pattern

Scott Bain discusses the essential features of the Command Pattern. Scott is a senior Disciplined Agile technical trainer and thought leader. This is part of a series of recorded presentations brought to you by PMI Disciplined Agile.

Contextual Forces


Motivation

Encapsulate an operational request of a Service into an entity (Command), so that the same Service can be used to trigger different operations. Optionally, this can be used to support undo, logging, queueing, and other additional behaviors. This is typically used to separate non-changing code (framework code) from changing code (plugin code) when a reusable object framework is created.

Encapsulation

The actual receiver of the service request is hidden from the delegating entity (aka "Invoker"), and also the presence or absence of logging, queueing, and other behaviors that can be hidden in the concrete Command entity. The Invoker is only coupled to the interface of the Abstract Command type.

Procedural Analog

When creating a reusable framework in a procedural system, quite often function pointers are used to redirect hard-coded functions to variable ones (aka a "callback"). This allows later developers to reuse the hard-coded routines in a new way by chaining the function pointer to redirect to new behavior. This is essentially what the Command pattern does, using encapsulated entites (objects, typically)

Non-Software Analog

CD players are built at the factory to accept a CD, but none (typically) is supplied by the manufacturer. These days, most people have access to a CD burner (as part of their desktop or laptop computer), and can make CD's that conform to the interface of a CD player. Thus, a person could buy a CD player, then burn a CD that contained any arbitrary audio information, and the player would be able to play it without any re-design.

 

player

Implementation Forces

Example

Command 1

class Invoker {
     private Command myCommand;
     public void setCommand(Command aCommand){
          myCommand = aCommand;
     }

     public void trigger(){

          myCommand.execute();
     }
}

absract class Command {
     abstract void execute();
}

class ConcreteCommand : Command {
     private Receiver myReceiver;
     public ConcreteCommand(Receiver aReceiver) {
          myReceiver = aReceiver;
     }

     public void execute() {
          myReceiver.operation();
     }
}

class Receiver {
     public operation() { // operation here }

}
class Client {
    public static void Main(String[] args) {
        Command c =
            new ConcreteCommand(new Receiver));
        Invoker i = new Invoker()
        i.setCommand(c);
        i.trigger()
    }
}

 

Questions, concerns, credibility checks

  • In order for the Command pattern to work, all concrete command objects will have to share the same execution interface, so as to make them interchangeable and extensible. If this would rob one or more of them of critical behavior, this pattern may not be workable.
  • How will the Invoker receive the Command object? Typically a setter() method is provided, but this is just one example. One can, for instance, parameterize the constructor of the Invoker to take the Command type. The question therefore is one of dynamisms (ability to change the Invoker frequently) vs. encapsulation (exposing this design to the Client objects, or potentially hiding it in an object factory - see Options in Implementation).
  • How will the concrete command object receive its intended Receiver? Typically this is an issue of construction, but a setter() method could be used, again the issue being dynamism vs. encapsulation.
  • Should there even be a seperate Receiver object? Sometimes the concrete command can implement the behavior without a receiver.
  • Do we want to support more complex options like undo, redo, and log? If so, these can be done in the encapsulated Command object, using undoable and redoable behavior on a given Receiver.

Options in implementation

The Command Pattern can be somewhat simplified if the concrete command object can directly implement the request:

Command 2 

This is particularly applicable if the operation is lightweight, and if the same receiver is not to be reused in in different ways. The opposite possibility is to make the concrete command objects relatively lightweight, and thus allow the same receiver to be used by more than one of them, but in a varying way:

Command 3

Also, as should not be surprising to readers of this repository, the Command as presented by the Gang of Four does not encapsulate the construction of the concrete commands and receivers used, which we would prefer. Thus, we will tend to add a factory of some kind, or at the very minimum a static getInstance() method on each type.

 

Consequent Forces


Testing issues

  • Pulling behavior out of the triggering framework (often graphical in nature), made the behavior easier to test on its own. As the Command Pattern does not specify the design of the behavioral objects, we often use other patterns to implement them (and so, those sections can be consulted here for testing advice).

Cost-Benefit (gain-loss)

  • Reuse of the triggering framework is easier, because there is no concrete coupling from a trigger to its behavior.
  • The same behavior can be used in different ways from different triggers.
  • The same trigger can cause different behaviors, especially when combined with The State Pattern
  • More objects are created, increasing complexity and potentially degrading performance