Command Objects Are Gerunds

A gerund—as I often have to remind myself—is a verbal noun. That is, a gerund is a verb being used as a noun. In English, gerunds always end in -ing, though not every word that ends in -ing is a gerund. An example: The verb “to overeat” becomes the gerund “overeating,” as in the sentence, “I enjoy overeating.”

The Command Pattern is a behavioral design pattern that works like a gerund because it takes the coding equivalent of a verb (method) and transforms it into the coding equivalent of a noun (object). This is its essence:

1class SomeCommand
2  def execute
3    # ...
4  end
5end

The idea is that you can make lots of command objects from this class (and other classes that adhere to this “has an execute method” interface), then pass them around your system to entities that know about the interface (i.e., know they can call execute on whatever object they are passed).

This transformation allows for some interesting possibilities. For example, you could dynamically build up a list of commands to be executed together at some later time, a structure that might form the basis for the creation and execution of user-defined macros. Another use with a similar structure is building up and executing a database transaction, where failure on the part of any individual command would prevent the transaction as a whole from being committed.

The Command Pattern can also be purposed to implement undo functionality. Each command object must remember the details of what it did when its execute method was called, and have an undo method to be able to reverse whatever it did.

The Wikipedia article on the Command Pattern contains a simple example of the pattern showing its typical structure. Here’s my version of the example, rewritten in Ruby and a little modified:

 1# Invoker
 2class Invoker
 3  def initialize
 4    @history = []
 5  end
 6
 7  def record_and_execute(command)
 8    @history << command  # Optional
 9    command.execute
10  end
11end
12
13# Receiver
14class Light
15  def turn_on
16    puts 'The light is on'
17  end
18
19  def turn_off
20    puts 'The light is off'
21  end
22end
23
24# A command
25class TurnOnCommand
26  def initialize(light)
27    @light = light
28  end
29
30  def execute
31    @light.turn_on
32  end
33end
34
35# Another command
36class TurnOffCommand
37  def initialize(light)
38    @light = light
39  end
40
41  def execute
42    @light.turn_off
43  end
44end
45
46# Client
47class Client
48  def initialize
49    @invoker = Invoker.new
50    @light = Light.new
51  end
52
53  def party
54    50.times do
55      @invoker.record_and_execute(TurnOnCommand.new(@light))
56      @invoker.record_and_execute(TurnOffCommand.new(@light))
57    end
58  end
59end

The example contains four sorts of entities, each with their own responsibility. The receiver does the actual work (in this case, it is a Light object that can be turned on and off). The command objects wrap method calls to the receiver. While client entities can already send a turn_on or turn_off message to a Lamp object, these commands are objects representing the sending of such a message. This may seem like a subtle distinction, but it's the key to how the pattern works.

The client makes decisions about which commands should be created and executed and when these things should occur, and the invoker is the entity that actually calls execute on the command objects. The roles of client and invoker are sometimes represented in the same object, but since they change for different reasons each responsibility should exist in its own entity.

The common thread running through this example and the use cases for the pattern described above is the decoupling of the actual execution of a command from the entity that decided it should be executed. As Uncle Bob puts it, the Command Pattern decouples “what gets done from who does it” and “what gets done from when it gets done.” The key to this decoupling is the reification of something abstract and transitory (a method) into a stable entity (the object).

Ben Spatafora, Software Craftsman

Ben Spatafora is a former 8th Light employee.

Interested in 8th Light's services? Let's talk.

Contact Us