Tags

  • AWS (7)
  • Apigee (3)
  • ArchLinux (5)
  • Array (6)
  • Backtracking (6)
  • BinarySearch (6)
  • C++ (19)
  • CI&CD (3)
  • Calculus (2)
  • DesignPattern (43)
  • DisasterRecovery (1)
  • Docker (8)
  • DynamicProgramming (20)
  • FileSystem (11)
  • Frontend (2)
  • FunctionalProgramming (1)
  • GCP (1)
  • Gentoo (6)
  • Git (15)
  • Golang (1)
  • Graph (10)
  • GraphQL (1)
  • Hardware (1)
  • Hash (1)
  • Kafka (1)
  • LinkedList (13)
  • Linux (27)
  • Lodash (2)
  • MacOS (3)
  • Makefile (1)
  • Map (5)
  • MathHistory (1)
  • MySQL (21)
  • Neovim (10)
  • Network (66)
  • Nginx (6)
  • Node.js (33)
  • OpenGL (6)
  • PriorityQueue (1)
  • ProgrammingLanguage (9)
  • Python (10)
  • RealAnalysis (20)
  • Recursion (3)
  • Redis (1)
  • RegularExpression (1)
  • Ruby (19)
  • SQLite (1)
  • Sentry (3)
  • Set (4)
  • Shell (3)
  • SoftwareEngineering (12)
  • Sorting (2)
  • Stack (4)
  • String (2)
  • SystemDesign (13)
  • Terraform (2)
  • Tree (24)
  • Trie (2)
  • TwoPointers (16)
  • TypeScript (3)
  • Ubuntu (4)
  • Home

    [Behavioral] Command

    Published Apr 13, 2022 [  DesignPattern  ]

    Real world example

    A generic example would be you ordering food at a restaurant. You (i.e. Client) ask the waiter (i.e. Invoker) to bring some food (i.e. Command) and waiter simply forwards the request to Chef (i.e. Receiver) who has the knowledge of what and how to cook. Another example would be you (i.e. Client) switching on (i.e. Command) the television (i.e. Receiver) using a remote control (Invoker).

    In plain words

    Allows you to encapsulate actions in objects. The key idea behind this pattern is to provide the means to decouple client from receiver.

    Wikipedia says

    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.

    Programmatic Example

    First of all we have the receiver that has the implementation of every action that could be performed

    // Receiver
    class Bulb {
        protected isOn: boolean = false;
    
        turnOn() {
            this.isOn = true;
            console.log("Bulb has been lit")
        }
    
        turnOff() {
            this.isOn = false;
            console.log("Darkness!")
        }
    
        getStatus(): boolean {
            return this.isOn
        }
    }
    

    then we have an interface that each of the commands are going to implement and then we have a set of commands

    interface Command {
        execute()
        undo()
        redo()
    }
    
    class TurnOn implements Command {
        protected bulb;
    
        constructor(bulb: Bulb) {
            this.bulb = bulb
        }
    
        execute() {
            this.bulb.turnOn();
        }
    
        undo(){
            this.bulb.turnOff()
        }
    
        redo(){
            this.execute()
        }
    }
    
    class TurnOff implements Command {
        protected bulb;
    
        constructor(bulb: Bulb) {
            this.bulb = bulb;
        }
    
        execute() {
            this.bulb.turnOff()
        }
    
        undo(){
            this.bulb.turnOn()
        }
    
        redo(){
            this.execute()
        }
    }
    

    Then we have an Invoker with whom the client will interact to process any commands

    class RemoteControl {
        submit(command: Command) {
            command.execute()
        }
    }
    

    Finally let’s see how we can use it in our client

    test('test command design patterns', () => {
        const bulb = new Bulb();
        const turnOn = new TurnOn(bulb)
        const turnOff = new TurnOff(bulb)
    
        const remoteControl = new RemoteControl()
    
        expect(bulb.getStatus()).toEqual(false)
        remoteControl.submit(turnOn)
        expect(bulb.getStatus()).toEqual(true)
        remoteControl.submit(turnOff)
        expect(bulb.getStatus()).toEqual(false)
    })
    

    Command pattern can also be used to implement a transaction based system. Where you keep maintaining the history of commands as soon as you execute them. If the final command is successfully executed, all good otherwise just iterate through the history and keep executing the undo on all the executed commands.

    References