Design Patterns: Command
• • 8 min readThere are 23 classic design patterns, which are described in the original book, Design Patterns: Elements of Reusable Object-Oriented Software
. These patterns provide solutions to particular problems, often repeated in the software development.
In this article, I am going to describe the how the Command Pattern; and how and when it should be applied.
Command Pattern: Basic Idea
In object-oriented programming, the command pattern is a behavioral design pattern in which an object is used to encapsulate all information needed to perform an action or trigger an event at a later time. This information includes the method name, the object that owns the method and values for the method parameters — Wikipedia
Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations - Design Patterns: Elements of Reusable Object-Oriented Software
In this pattern an abstract Command
class is declared as an interface for executing operations. The Command
class defines a method named execute
, which must be implemented in each concrete command. This execute
method is a bridge between a Receiver
object and an action. The Receiver
knows how to perform the operations associated with a request (any class may be a Receiver
). Another relevant component in this pattern is the Invoker
class which asks for the command that must be executed.
The UML diagram for this pattern is the following one:
Command Pattern: When To Use
The Command Pattern should be used when:
- You need a command to have a life span independent of the original request. Furthermore, if you want to queue, specify and execute requests at different times.
- You need undo/redo operations. The command's execution can be stored for reversing its effects. It is important that the
Command
class implements the methods undo and redo. - You need to structure a system around high-level operations built on primitive operations.
Command Pattern: Advantages
The Command Pattern has several advantages, summarised in the following points:
- It decouples the classes that invoke the operation from the object that knows how to execute the operation
- It allows you to create a sequence of commands by providing a queue system
- Implementing extensions to add a new command is easy and can be done without changing the existing code.
- You can also define a rollback system with the Command pattern, like in the Wizard example, we could write a rollback method.
- Have strict control over how and when commands are invoked.
- The code is easier to use, understand and test since the commands simplify the code.
Command pattern - Example 1: A Stock Market
I will now show you how you can implement this pattern using JavaScript/TypeScript. In our case, I have made up a problem in which there is a class named Agent
which defines the attributes: stockTrade
; and an operation placeOrder
. This class is the bridge between client/context and the StockTrader
. The placeOrder
method is responsible for deciding what action should to be executed. For example, if the orderType
is buy
or sell
the method should invoke the action in the StockTrader
. The following UML diagram shows the scenario that I have just described.
The client
and Agent
codes are the following ones:
import { Agent } from './agent.class';
const agent = new Agent();
agent.placeOrder('buy');
agent.placeOrder('sell');
import { StockTrade } from '../command-solution-1/stock.trader.class';
// Invoker.
export class Agent {
private stockTrade: StockTrade = new StockTrade();
public constructor() {}
placeOrder(orderType: string): void {
if (orderType === 'buy') {
this.stockTrade.buy();
} else if (orderType === 'sell') {
this.stockTrade.sell();
} else {
console.log('OPERATION NOT FOUND!');
}
}
}
The most relevant code smell is the placeOrder
method which is coupled to the actions/commands from StockTrade
. There are different techniques to avoid this code smell.In this case, the Command
pattern is a good solution, since we want to log the command's history.
Finally, the StockTrade
class is the following one:
export class StockTrade {
buy() {
console.log('You want to buy stocks');
}
sell() {
console.log('You want to sell stocks ');
}
}
The result obtained is shown in the following image:
Command pattern - Example 1: A Stock Market - Solution
The idea to decouple the commands from the Agent
class is to create a set of classes for each command. However, the commands share a common interface which allows us to execute the action depending on each concrete command.
That is the reason why we have created the Order
abstract class which will have an abstract method called execute
. This method is the one that will be invoked from the Agent
class (the invoker). Furthermore, Agent
class will have a list of commands to obtain the command's history.
This way, the agent delegates the responsibility of knowing which operation has to be executed on the object it receives. The main change is that Agent
class will no longer receive a primitive attribute as a parameter (string), since this has no semantic value. Instead, the Agent
class will now receive a command object as a parameter, which provides semantic value.
The new UML diagram using the command pattern is shown below:
The code associate to the client
is the following one:
import { Agent } from './agent.class';
import { BuyStockOrder } from './buy-stock-order';
import { SellStockOrder } from './sell-stock-order';
import { StockTrade } from './stock.trader.class';
const stock = new StockTrade();
const buyStock = new BuyStockOrder(stock);
const sellStock = new SellStockOrder(stock);
const agent = new Agent();
agent.placeOrder(buyStock); // Buy Shares
agent.placeOrder(sellStock); // Sell Shares
console.log(agent.listOrders());
In this case each order
receives the StockTrade
using DI (Dependency Injection). The Agent
invokes the command using the placeOrder
method, which performs the operation though the execute
method.
The code associated with the Agent
is the following one:
import { Order } from './order.class';
// Invoker.
export class Agent {
private orders: Order[] = [];
public constructor() {}
placeOrder(order: Order) {
this.orders.push(order);
order.execute();
}
listOrders(): string {
return this.orders.reduce((acc, curr) => acc + curr.toString() + '\n', '');
}
}
You may note that the if-elseif-else
control structure is avoided by using the order.execute
method, which delegates the responsibility to each command.
The code associated to the Order
and each order are the following ones:
export abstract class Order {
protected uid = Math.floor(Math.random() * 100000);
protected type: string;
public toString(): string {
return 'UID: ' + this.uid + ' - Operation: ' + this.type;
}
abstract execute();
}
import { Order } from './order.class';
import { StockTrade } from './stock.trader.class';
//ConcreteCommand Class.
export class BuyStockOrder extends Order {
private stock: StockTrade;
protected type: string;
public constructor(stockTrade: StockTrade) {
super();
this.stock = stockTrade;
this.type = 'Buy';
}
public execute(): void {
this.stock.buy();
}
}
import { Order } from './order.class';
import { StockTrade } from './stock.trader.class';
//ConcreteCommand Class.
export class SellStockOrder extends Order {
private stockTrade: StockTrade;
protected type = 'sell';
public constructor(stockTrade: StockTrade) {
super();
this.stockTrade = stockTrade;
}
public execute() {
this.stockTrade.sell();
}
}
The StockTrade
class is not modified in this command. So, the result after these modifications in the execution of the program is shown in the following image:
npm run example1-problem
npm run example1-command-solution1
Command pattern - Example 2: R2D2 commands!
Another interesting example which is resolved using command pattern is when there are several commands to execute for a robot.
For example, a set of commands as SaveSecret, Clean and Move are asked to a famous robot, R2D2. In the following UML diagram you can see this situation:
The code associated to the clients is the following:
import { CleanCommand, MoveCommand, SaveSecretCommand } from './commands';
import { R2D2Service, StoreService } from './services';
import { R2D2 } from './r2d2';
const storeService = new StoreService();
const r2d2Service = new R2D2Service();
const saveSecretCommand = new SaveSecretCommand(storeService);
const cleanCommand = new CleanCommand(r2d2Service);
const moveCommand = new MoveCommand(r2d2Service);
const r2d2 = new R2D2();
r2d2.excuteCommand(saveSecretCommand, { message: 'SuperSecretMessage' });
r2d2.excuteCommand(cleanCommand);
r2d2.excuteCommand(moveCommand, { direction: 'Málaga, Paradise' });
console.log(r2d2.listCommands());
In this example, there are three commands (saveSecretCommand, cleanCommand and moveCommand), two services (StoreService and R2D2Service) and an Agent (R2D2).
The Agent invokes the orders using the executeCommand
method which receives two arguments: 1) The command; 2) The parameters to carry out the previous command.
Therefore, the code associated to the R2D2 is the following one:
import { Command } from './commands/command.class';
export class R2D2 {
private commands: Command[] = [];
public constructor() {}
excuteCommand(command: Command, commandArgs?: any): void {
this.commands.push(command);
command.execute(commandArgs);
}
listCommands(): string {
return this.commands.reduce(
(acc, curr) => acc + curr.toString() + '\n',
''
);
}
}
R2D2 has a list of commands, which may be listed through the listCommands
method, and stored using the commands
data-structure. Finally, the executeCommand
method is responsible for invoking the execute method of each command.
So, the next step is to create the code associated to the command (abstract class) and each concrete command:
export abstract class Command {
protected uid = Math.floor(Math.random() * 100000);
public toString(): string {
return 'R2D2: Command UID:: ' + this.uid;
}
abstract execute(args): void;
}
/**/
import { Command } from './command.class';
import { R2D2Service } from '../services';
export class CleanCommand extends Command {
public constructor(private r2d2Service: R2D2Service) {
super();
}
public execute(): void {
console.log('Execute -> Clean Command');
this.r2d2Service.clean();
console.log();
}
}
/**/
import { Command } from './command.class';
import { R2D2Service } from '../services';
export class MoveCommand extends Command {
public constructor(private r2d2Service: R2D2Service) {
super();
}
public execute({ direction }: { direction: string }): void {
console.log('Execute -> Move Command');
this.r2d2Service.move(direction);
console.log();
}
}
/**/
import { Command } from './command.class';
import { StoreService } from '../services/store.service';
export class SaveSecretCommand extends Command {
public constructor(private storeService: StoreService) {
super();
}
public execute({ message }: { message: string }): void {
console.log('Execute -> Execute Command...');
this.storeService.storeMessage(message);
console.log();
}
Finally, each command invokes the service responsible for the action, in this case we have used two different services to show that not all the commands delegate responsibility to the same service or class.
export class R2D2Service {
constructor() {}
clean() {
console.log('R2D2Service -> Clean ');
}
move(direction: string) {
console.log('R2D2Service -> Move: ', direction);
}
}
/**/
export class StoreService {
constructor() {}
storeMessage(message: string) {
console.log('StoreService -> StoreMessage: ', message);
}
}
The result obtained is shown in the following image:
I have created a npm scripts that run the example shown here after applying the command pattern.
npm run example2-command-solution-1
Conclusion
The command pattern can avoid complexity in your projects because you encapsules the commands in specific class which can be added/removed or changed in any moment (including execution-time).
The most important thing is not implementing the pattern as I have shown you, but to be able to recognise the problem which this specific pattern can resolve, and when you may or may not implement said pattern. This is crucial, since implementation will vary depending on the programming language you use.
More more more...
- Design Patterns: Elements of Reusable Object-Oriented Software by Gamma, Helm, Johnson, & Vlissides, Addison Wesley, 1995.
- The Command Pattern — Wikipedia.
- https://www.dofactory.com/javascript/command-design-pattern
- https://github.com/sohamkamani/javascript-design-patterns-for-humans#-command
The GitHub branch of this post is https://github.com/Caballerog/blog/tree/master/command-pattern