Command Pattern

The Command Pattern is a data-driven design pattern, which belongs to the category of behavioral patterns. It is also known as the Action Pattern or the Transaction Pattern. The Command Pattern wraps a request in the form of a command within an object and passes it to the invoking object. The invoking object then looks for a suitable object that can handle the command and passes the command to the appropriate object. The object then queues the request or logs the request and supports undo operations.

Description

In software design, we often need to send requests to some objects without knowing who the receiver of the request is, or what operation is being requested. We only need to specify the specific request receiver at runtime. In such cases, the Command Pattern can be used to eliminate the coupling between the sender and receiver of the request, making the calling relationship between objects more flexible. The Command Pattern fully decouples the sender and receiver, removing direct reference relationships between them. The object sending the request only needs to know how to send the request, without needing to know how to fulfill the request. The Command Pattern can also be used to implement transaction-based systems. Once a command is executed, the history of the command is retained. If the command is successfully executed, everything is fine; otherwise, the history can be traversed, and the executed commands can be undone.

Advantages

  • Reduces the coupling in the system.
  • New commands can easily be added to the system.
  • It is relatively easy to design a command queue and macro commands (composite commands).
  • Enables easy implementation of Undo and Redo for requests.

Disadvantages

  • Using the Command Pattern may lead to an excessive number of concrete command classes in some systems. This is because a specific command class needs to be designed for each command. Thus, some systems may require a large number of concrete command classes, which can affect the use of the Command Pattern.

Applicable Environment

  • The system needs to decouple the request caller and receiver, so that they do not interact directly.
  • The system needs to specify requests at different times, queue requests, and execute requests.
  • The system needs to support Undo and Redo operations for commands.
  • The system needs to combine a set of operations, i.e., support macro commands.

Implementation

// Assume we have a light bulb and we want to control it using a remote control

class Bulb {
    turnOn() {
        console.log("Bulb has been lit!");
    }
    
    turnOff() {
        console.log("Darkness!");
    }
}

class Command {
    execute(){
        throw new Error("Abstract method cannot be called");
    }

    redo(){
        throw new Error("Abstract method cannot be called");
    }

    undo(){
        throw new Error("Abstract method cannot be called");
    }
}

class TurnOnCommand extends Command{
    constructor(bulb) {
        super();
        this.bulb = bulb;
    }
    
    execute() {
        this.bulb.turnOn();
    }
    
    undo() {
        this.bulb.turnOff();
    }
    
    redo() {
        this.execute();
    }
}

class TurnOffCommand extends Command {
    constructor(bulb) {
        super();
        this.bulb = bulb;
    }
    
    execute() {
        this.bulb.turnOff();
    }
    
    undo() {
        this.bulb.turnOn();
    }
    
    redo() {
        this.execute();
    }
}

class RemoteControl {
    submit(command) {
        command.execute();
    }
}

(function(){
    var bulb = new Bulb();

    var turnOn = new TurnOnCommand(bulb);
    var turnOff = new TurnOffCommand(bulb);

    var remote = new RemoteControl();
    remote.submit(turnOn); // Bulb has been lit!
    remote.submit(turnOff); // Darkness!
})();

Daily Question

https://github.com/WindrunnerMax/EveryDay

References

https://www.runoob.com/design-pattern/command-pattern.html https://github.com/sohamkamani/javascript-design-patterns-for-humans#-command https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/command.html