Implementation

To show the Command design pattern in action, we will implement a fake graphics editor. The editor itself is super-ultra-mega-duper simplified (well, Photoshop should have started from something, right?) and provides the following functionality:

There is only one shape visible on the screen which cannot be removed, but its parameters (colour, height and width) could be adjusted using buttons;

Change the shape’s colour to a random one;

Change the shape’s height to a random value between 50 and 150;

Change the shape’s width to a random value between 50 and 150;

All of the operations could be undone using the Undo button.

And that is basically it. I know, as a graphics editor, this one sounds terrible, but it would be more than enough to demonstrate the purpose of the Command design pattern.

The main idea behind the implementation of the mentioned graphics editor is to separate the actual business logic of the button from its representation. To achieve this, each operation (request) of the button is encapsulated in a separate class object. Also, by using the Command design pattern, the implementation of undo operation is possible — since every command is encapsulated in a separate class, it is easy to store an objects’ list of already executed commands as well as undoing the last operation by taking the last command from the list and calling the undo() method on it.

Let’s check the class diagram first and then investigate each class/component to see how the Command design pattern could help us building such a graphics editor.

Class diagram

The class diagram below shows the implementation of the Command design pattern:

Class Diagram — Implementation of the Command design pattern

Command is an abstract class which is used as an interface for all the specific commands:

execute() — an abstract method which executes the command;

getTitle() — an abstract method which returns the command’s title. Used in command history UI;

undo() — an abstract method which undoes the command and returns the receiver to the previous state.

ChangeColorCommand, ChangeHeightCommand and ChangeWidthCommand are concrete command classes which implement the abstract class Command and its methods.

Shape is a receiver class which stores multiple properties defining the shape presented in UI: color, height and width.

CommandHistory is a simple class which stores a list of already executed commands (commandList) and provides methods to add a new command to the command history list (add()) and undo the last command from that list (undo()).

CommandExample initializes and contains CommandHistory, Shape objects. Also, this component contains multiple PlatformButton widgets which have a specific implementation of Command assigned to each of them. When the button is pressed, the command is executed and added to the command history list stored in CommandHistory object.

Shape

A simple class to store information about the shape: its color, height and width. Also, this class contains a named constructor to create a shape object with pre-defined initial values.

Command

An interface which defines methods to be implemented by the specific command classes. Dart language does not support the interface as a class type, so we define an interface by creating an abstract class and providing a method header (name, return type, parameters) without the default implementation.

Commands

ChangeColorCommand — a specific implementation of the command which changes the color of the Shape object.

ChangeHeightCommand — a specific implementation of the command which changes the height of the Shape object.

ChangeWidthCommand — a specific implementation of the command which changes the width of the Shape object.

CommandHistory

A simple class which stores a list of already executed commands. Also, this class provides isEmpty and commandHistoryList getter methods to return true if the command history list is empty and return a list of command names stored in the command history respectively. A new command could be added to the command history list via the add() method and the last command could be undone using the undo() method (if the command history list is not empty).

Example

First of all, a markdown file is prepared and provided as a pattern’s description:

CommandExample contains CommandHistory and Shape objects. Also, this widget contains several PlatformButton components, each of which uses a specific function executing a concrete command. After the command’s execution, it is added to the command history list stored in the CommandHistory object. If the command history is not empty, the Undo button is enabled and the last command could be undone.

The client code (UI elements, command history, etc.) isn’t coupled to concrete command classes because it works with commands via the command interface. This approach allows introducing new commands into the application without breaking any existing code.

As you can see in the example, by triggering a specific command, its object is created, executed and added to the command history list. Hence, it is possible to undo the command even though it was executed several steps before — that’s one of the advantages of using the Command design pattern.

All of the code changes for the Command design pattern and its example implementation could be found here.