Command

AKA: Action, Transaction

When you know there’s an action or sequence of actions to take but not what they are or even which objects they operate on; you need some way to store the target object of the activity, the method to call, and the parameters to apply. One way to represent this information is by a command object. Consider a command line interface: it includes the operation, its target or targets, and the necessary parameters. In effect, a shell script is a sequence of actions to take. But how do we represent that inside our application?

We can store references to our recipient objects and function pointers to methods to call as long as they all have the same signature, e.g. you could require they all take dictionaries of parameters. This can work in some systems for a while if the types match. But at some point, the recipient’s base class or the method’s parameters will deviate and then you won’t know how to store or call the function. You will then be unsure how to reference the recipient safely.

Instead of attempting to store the parts of the puzzle, introduce a Command object which abstracts the execution and allows the concrete command objects to handle how they refer to their recipient, how they call the required method, and how they hold the parameters to use.

Command

Adding undo can be achieved by adding an Unexecute method and reversing the operation. The GoF book suggests using a Memento for this purpose. However, sometimes things cannot be put back. Bills cannot be unpaid, and secret data cannot be undeleted. But even if some things cannot be undone, their impact can be somehow recognised and fixed.

There are some pitfalls with Command objects in that they do not always capture the sequence of events in a usable way if not designed very carefully. For example, if used in a do/undo system, commands that create objects can cause complications with commands that affect those objects. When creating, modifying, undoing twice, and then redoing twice, there’s sometimes a problem with the second redo—reapplying an action on a recreated object. The command to redo must operate on a recipient potentially destroyed as part of undoing the construction command. This non-trivial problem affects anything that creates mutable instances.

The fact these problems weren’t talked about in the GoF book makes me question whether the undo systems were implemented fully, as those bugs appear very quickly. Or perhaps construction commands never came up in their implementations.

My wisdom on this subject is to refer to objects by handles using unique IDs and never pointers. Creation commands will re-create a different object but can always return it to the document with the same unique ID.

This lack of prescience is a diagnostic point for me. We can condemn patterns when their descriptions lack any representation of common bugs. If most pattern implementations produce a set of regularly encountered sticking points and those issues are not covered in the pattern prose then the pattern is incomplete and needs updating. Or perhaps it was a hopeful pattern extrapolated from the mind rather than a direct experience.

“I will do it. What? To whom? That’s my job to know.”