Design Pattern: Command Pattern in TypeScript

Command pattern wraps the full request in an object. This makes the request/command a self-contained element, and can be used/passed at any time without any dependency.

This article demonstrates Command pattern implementations in TypeScript. Check the following examples.

Implementation

Follow the steps below-

  • Define an interface for the command classes, which will ensure a common interface for all the commands.
  • In the interface declare methods as per requirement. Make sure to add a method for the command execution and one method for undoing the command.
  • Create command classes and implement the interface. This implementation will ensure the execution and undo process of the command.
  • Create a command control class. 
  • In the command control class maintain a list of commands which are executed.
  • In the command control class, add methods for adding and removing commands. Execute the command when it’s added and perform undo when a command is removed/undone.

Examples

Here are a few examples of Command pattern implementations.

Example #1: UI Elements

Let’s take the example of printing UI elements. We have commands for UI elements like – button, input box, table.

Command Interface

  • Create file “ui-command.ts”.
  • Define interface “UiCommand”.
  • Declare methods – “print” (for printing the element), “remove” (for removing the element).
// ui-command.ts

interface UiCommand {
    print();
    remove();
}

export default UiCommand;

Button Concrete Class

  • Create file “button-ui.ts”.
  • Create class “ButtonUi”.
  • Implement interface “UiCommand” for the class. Define method “print” and “remove” for the implementation.
// button-ui.ts

import UiCommand from "./ui-command";

class ButtonUi implements UiCommand {
    private name: string;
    constructor(name: string) {
        this.name = name;
    }
    public print() {
        console.log("Printing " + this.name + " Button");
    }
    public remove() {
        console.log("Removing " + this.name + "  Button");
    }
}

export default ButtonUi;

Input Element Concrete Class

  • Create file “input-ui.ts”.
  • Create class “InputUi”.
  • Implement “UiCommand” interface for the class.
// input-ui.ts

import UiCommand from "./ui-command";

class InputUi implements UiCommand {
    public print() {
        console.log("Printing Input");
    }
    public remove() {
        console.log("Removing Input");
    }
}

export default InputUi;

Table Element Concrete Class

  • Create file “table-ui.ts”.
  • Create class “TableUi” and implement “UiCommand” for it.
// table-ui.ts

import UiCommand from "./ui-command";

class TableUi implements UiCommand {
    public print() {
        console.log("Printing Table");
    }
    public remove() {
        console.log("Removing Table");
    }
}

export default TableUi;

UI Element Control Class

  • Create file “ui-control.ts”.
  • Create class “UiControl”.
  • Define a private property named “commandList”. This will be used to store all the commands which are executed. And commands will be removed from the list when undone.
  • Define method “addElement”, which accepts a command and executes the “print” method of the command. This command is pushed to the “commandList” after execution.
  • Define method “removeElement”. Execute the “remove” method of the command in the implementation and remove it from “commandList” at the end.
  • Define an “undo” method, which uses the “removeElement” method inside it.
// ui-control.ts

import UiCommand from "./ui-command";

class UiControl {
    private commandList: UiCommand[] = [];

    public addElement(command: UiCommand) {
        command.print();

        this.commandList.push(command);
    }

    public removeElement(command: UiCommand) {
        command.remove();

        for (let i = 0; i < this.commandList.length; i++) {
            if (command == this.commandList[i]) {
                this.commandList.splice(i, 1);
                break;
            }
        }
    }

    public undo() {
        const lastCommand = this.commandList[this.commandList.length - 1];
        this.removeElement(lastCommand);
    }
}

export default UiControl;

Demo

Create an object of “UiControl”. Also create some command objects and add those to the “UiControl” object using the “addElement” method for the execution.

The commands can be removed after being added.

// demo.ts

import ButtonUi from "./button-ui";
import InputUi from "./input-ui";
import TableUi from "./table-ui";
import UiControl from "./ui-control";

const uiControl = new UiControl();

const inputUi = new InputUi();
const tableUi = new TableUi();
const buttonUi = new ButtonUi("Submit");

uiControl.addElement(inputUi);
uiControl.addElement(tableUi);
uiControl.addElement(buttonUi);
uiControl.removeElement(tableUi);

uiControl.addElement(new ButtonUi("Cancel"));
uiControl.addElement(new TableUi());
uiControl.addElement(new InputUi());
uiControl.addElement(new ButtonUi("Wrong button"));

uiControl.undo();
uiControl.undo();

Output

The following output will be generated.

Printing Input
Printing Table
Printing Submit Button

Removing Table

Printing Cancel Button
Printing Table
Printing Input
Printing Wrong button Button

Removing Wrong button  Button
Removing Input

Source Code

Use the following link to get the source code:

Other Code Implementations

Use the following links to check Command pattern implementation in other programming languages.

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.