DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Cover image for Command Pattern
Francesco Ciulla
Francesco Ciulla

Posted 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

Top comments (0)

Timeless DEV post...

How to write a kickass README

Arguably the single most important piece of documentation for any open source project is the README. A good README not only informs people what the project does and who it is for but also how they use and contribute to it.

If you write a README without sufficient explanation of what your project does or how people can use it then it pretty much defeats the purpose of being open source as other developers are less likely to engage with or contribute towards it.