8th Light. 8th Light logo

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:

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

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
 2 class Invoker
 3   def initialize
 4     @history = []
 5   end
 7   def record_and_execute(command)
 8     @history << command  # Optional
 9     command.execute
10   end
11 end
13 # Receiver
14 class Light
15   def turn_on
16     puts 'The light is on'
17   end
19   def turn_off
20     puts 'The light is off'
21   end
22 end
24 # A command
25 class TurnOnCommand
26   def initialize(light)
27     @light = light
28   end
30   def execute
31     @light.turn_on
32   end
33 end
35 # Another command
36 class TurnOffCommand
37   def initialize(light)
38     @light = light
39   end
41   def execute
42     @light.turn_off
43   end
44 end
46 # Client
47 class Client
48   def initialize
49     @invoker = Invoker.new
50     @light = Light.new
51   end
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
59 end

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