DEV Community

Cover image for 12 - Command
Mangirdas Kazlauskas 🚀
Mangirdas Kazlauskas 🚀

Posted on • Originally published at Medium

12 - Command

Previously in the series, I have analysed and implemented one of the most popular and useful creational design patterns — Abstract Factory. This time, I would like to introduce an OOP design pattern that belongs to the category of behavioural design patterns — the Command.

Table of Contents

  • What is the Command design pattern?
  • Analysis
  • Implementation
  • Your Contribution

What is the Command design pattern?

A Dangerous Command

Command, also known as Action or Transaction, is one of the behavioural design patterns which intention is described in the GoF book:

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable opera­tions.

That is, by encapsulating the request as an object, the client is completely decoupled from any of the details of how that command is implemented or how it will get executed — the client doesn’t have to care about any dependencies.

There are multiple components of which the Command design pattern is consisted of. Usually, Command objects serve as links between various UI and business logic objects. In this case, the command object could be bound to the UI element at runtime by the Client and that particular UI component, called Sender, invokes the request. The Sender triggers the assigned Command instead of sending the request directly to the Receiver - a simple or complex object which contains the actual logic for the request to be fulfilled. A specific Command passes the call to the receiver which does the actual work. As a result, commands become a convenient middle layer that reduces coupling between the UI and business logic layers.

Let’s move to the analysis and implementation parts to understand the details about this pattern and learn how to implement it!

Analysis

The general structure of the Command design pattern looks like this:

Command Class Diagram

  • Command — declares an interface for executing an operation;
  • Concrete Commands (Command1/Command2) — implement various kinds of requests by invoking the corresponding operation(s) on Receiver;
  • Invoker — the sender class which triggers the Command instead of sending the request directly to the Receiver;
  • Receiver — knows how to perform the operations associated with carrying out a request. Any class may serve as a Receiver;
  • Client — creates a Concrete Command object and sets its Receiver.

Applicability

The Command design pattern could be used when you want to parameterize objects by an action to perform. That is, the operation (command) is extracted to a separate class which object could be passed as a method argument, stored inside another object or the linked command could be switched at runtime.

Furthermore, the Command design pattern is useful when you want to queue operations, schedule their execution, or execute them remotely. Since the command itself is just a simple class, its object (as any other object) could be serialized, stored, e.g. in the database or a text file and later restored as the initial command and executed. This is useful when you want to schedule a specific task that should be executed at a particular time, or on a recurring schedule.

Also, one of the most popular use-case for the Command is to use it for creating reversible operations. To be able to revert operations, you need to implement the history of performed operations. The command history is a stack that contains all executed command objects along with related backups of the application’s state.

Finally, the Command design pattern helps you write cleaner and reusable code. By using this pattern, you propagate the Single Responsibility Principle (the operation logic is decoupled from the component which performs that particular operation) and the Open/Closed Principle (introducing new commands to the application does not require changing the existing code).

Implementation

Let's Have Some Fun

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:

Command Implementation Class Diagram

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

  • execute() — an abstract method that executes the command;
  • getTitle() — an abstract method that returns the command’s title. Used in command history UI;
  • undo() — an abstract method that undoes the command and returns the receiver to the previous state.

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

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

CommandHistory is a simple class that 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.

shape.dart

Command

An interface that 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.

command.dart

Commands

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

change_color_command.dart

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

change_height_command.dart

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

change_width_command.dart

CommandHistory

A simple class that 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).

command_history.dart

Example

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

Command Markdown

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.

command_example.dart

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.

Command Example

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.

Your Contribution

💖 or 🦄 this article to show your support and motivate me to write better!
💬 Leave a response to this article by providing your insights, comments or wishes for the next topic.
📢 Share this article with your friends, colleagues on social media.
➕ Follow me on dev.to or any other social media platform.
⭐ Star the Github repository.

Top comments (0)