Skip to content

Command

Cyril Chubenko (ViXP) edited this page Nov 13, 2017 · 7 revisions

Problem

The client needs to operate the object (or family of objects) during runtime, as well as to cancel the operations one-by-one or all at once, by using the simple interface of a single object.

Pattern idea

When we have the objects (receivers) with a huge amount of operations in them we can define the class of command objects, which will share the client-needed interface of executing and canceling the operations of receivers. Each command for each operation. As all of the receivers have the same class (or inherit from the same class), there is no need to create the command object for every single receiver (or the final quantity of commands will be the number of receivers multiplied by number of operations). It's much more clever to use the concrete receiver as the dependency injection to the command object (or by passing the receiver to the command's constructor during the instantiation) and to use the advantages of polymorphism in the command object.

If the details of canceling the operation varies from one receiver to another, the command object, which encapsulates the concrete operation of canceling mechanism won't be suitable for some receivers, so it is also not expedient to encapsulate neither the operation nor the undoing operation of receiver inside the command object. It is much better to leave both methods encapsulated in the receiver itself (all receivers must be modified with undoing operations methods) and to use them polymorphically in the command object.

Finally the command objects will be very light and their responsibility will be only to execute the concrete methods of receiver for execution and undoing operations.

However, our client wants to have the single entry point for all operations and we still didn't solve the problem of how to save the history of executed commands, to run the undoing methods of them when it will be needed. So it is time to use the new abstraction, invoker - the object which will encapsulate the history of executed commands (in some data structure, as ex. simple array), and will be responsible for executing the concrete command (passed as argument), and also will be responsible for cancelling the commands by getting the last one from history and running the undoing method on it, or by some other canceling logic.

In the end, for executing the operation, client must use the execution method of the invoker, by passing the concrete command object to it (and by passing the concrete receiver object to command). For canceling - must execute the undoing method of invoker (with, or without parameters).

The backside of this pattern is that client must know all the classes of commands and receivers, but this problem may be solved with an other design pattern (ex. Factory Method, Facade, Mediator etc.)

Generalization

  • Receiver - the large object (or family of objects), which encapsulates the logic of operations and the logic of the operations cancelling.
  • Command - the family of objects, every one of which executes the one concrete operation of gotten receiver, and one concrete cancelling operation of gotten receiver.
  • Invoker - the single entry point object, which saves the history of executed commands, implements the interface of running the execution method of gotten command and running the cancelling method of command from history.
  • Client - uses the invoker's interface to execute the command (passes the concrete command and concrete receiver to invloker) and to cancel the command.

Concepts of Object Oriented Programming applied

polymorphism delegation encapsulation abstraction inheritance

My example

The source code

Simple pseudographical editor which can execute commands specified by user input, undo them and redo them.

Objects, classes, and interfaces

Drawer - the abstract Receiver, implements the common methods of all concrete receivers. TopLeftCornerDrawer, TopRightCornerDrawer, BottomLeftCornerDrawer, BottomRightCornerDrawer, SpotFillDrawer,HorizontalLineDrawer, VerticalLineDrawer, SolidFillDrawer - the concrete Receivers, inherit the Drawer class, are responsible for drawing the concrete symbols. DrawerCommand - the abstract Command, defines the common interface for concrete commands, and implements the common constructor. SymbolDrawerCommand, SpaceDrawerCommand, BreakLineDrawerCommand - the concrete Commands, responsible for executing the different kind of symbols drawing of different receivers. CommandInvoker - the concrete Invoker, is responsible for undoing, redoing and history saving operations.

The details of implementation

For this implementation I've also introduced the Stream singleton object which has nothing to do with pattern, but is used for proper work of CLI. Here I decided not to instantiate the receivers and to use it in a singleton way, as well, as the invoker object. This example is interactive, so you can try it yourself.

Clone this wiki locally