DEV Community

Cover image for Command Pattern
Francesco Ciulla
Francesco Ciulla

Posted on • Updated on

Command Pattern

Design Pattern

Capture Actions

GitHub Repository: https://github.com/FrancescoXX/Design-Patterns-Command-Javascript


Behavioral Design Pattern

⚡️Recognize

  • We want to implement a set of operation, with an undo function

💡Intent

  • Encapsulate operations with an object
  • Let the client pass parameters to these operations
  • Queue the requests (history)
  • Support the undo functionality (undoCommand)

🔧 Apply when

  • Save the State (state.value)
  • Queue requests (commands' history)
  • Want Command as a parameter
  • Pass command like general object
  • Need Undo functionality

✅Pro

  • Decoupling between
    • Object that invokes the operation (Store)
    • Object that knows how to perform it (Command)
  • We can create a new command which is a composition of commands easily

🏆 Great for

  • Centralize the actions which changes the state
  • Capture subsequent requests and keep track of them

/** Command Pattern
 *  Behavioral Pattern
 */

//In this class, we store the value and the history of commands
class StoreCalculator {
  constructor() {
    this.value = 0;
    this.commands = [];
  }

  //Store the new value and Execute the specific Command
  storeAndExecute = (command) => {
    this.value = command.exec(this.value); //Store
    this.commands.push(command); //Execute
  }

  //Undo Command
  undoCommand = () => this.value = this.commands.pop().undo(this.value);
}

/** Command to add a value
 * @param {number} opValue value to add
 */
class AddOperation {
  constructor(opValue) {
    this.opValue = opValue;
  }
  exec = (val) => val + this.opValue;
  undo = (val) => val - this.opValue;
}

/** Command to subtract a value
 * @param {number} opValue value to subtract
 */
class SubOperation {
  constructor(opValue) {
    this.opValue = opValue;
  }
  exec = (val) => val - this.opValue;
  undo = (val) => val + this.opValue;
}

/** Command to multiply a value
 * @param {number} opValue value to multiply
 */
class MulOperation {
  constructor(opValue) {
    this.opValue = opValue;
  }
  exec = (val) => val * this.opValue;
  undo = (val) => val / this.opValue;
}

/**  Command to divide for a value
 * @param {number} opValue value to divide
 */
class DivOperation {
  constructor(opValue) {
    this.opValue = opValue;
  }
  exec = (val) => val / this.opValue;
  undo = (val) => val * this.opValue;
}

//MAIN

//Create a new Calculator
const store = new StoreCalculator();

store.storeAndExecute(new AddOperation(30)); //store.value = 30
store.storeAndExecute(new SubOperation(10)); //store.value = 20
store.storeAndExecute(new MulOperation(10)); //store.value = 200
store.storeAndExecute(new DivOperation(2));  //store.value = 100

store.undoCommand(); // UNDO: remove last operation. calculator value now is 100 again

console.log(store.value); //100
Enter fullscreen mode Exit fullscreen mode

GitHub Repository: https://github.com/FrancescoXX/Design-Patterns-Command-Javascript

Latest comments (0)