跳至主要內容

命令模式

h7ml设计模式frontend设计模式frontend大约 2 分钟约 472 字

命令模式主要应用在需要延迟执行请求、支持撤回的场景中,可能在文本编辑器中有应用,我目前没有使用过,这里就留坑了。

命令模式本质上就是将数据和操作封装为一个对象,实现操作的撤回、延迟等。

这里贴一下 Youtube 一个博主举的 计算器例子open in new window

首先是一个支持加减乘除的计算器:

class Calculator {
  constructor() {
    this.value = 0;
  }

  add(valueToAdd) {
    this.value = this.value + valueToAdd;
  }

  subtract(valueToSubtract) {
    this.value = this.value - valueToSubtract;
  }

  multiply(valueToMultiply) {
    this.value = this.value * valueToMultiply;
  }

  divide(valueToDivide) {
    this.value = this.value / valueToDivide;
  }
}

const calculator = new Calculator();
calculator.add(10);
console.log(calculator.value); // 10
calculator.divide(2);
console.log(calculator.value); // 5

如果需要给计算器增加撤回的功能,就可以使用命令模式了。

我们把每一步操作都封装为一个类作为命令对象,类中包含了操作数和操作方法,然后用一个数组记录所有的命令对象。

class Calculator {
  constructor() {
    this.value = 0;
    this.history = [];
  }

  executeCommand(command) {
    this.value = command.execute(this.value);
    this.history.push(command);
  }

  undo() {
    const command = this.history.pop();
    this.value = command.undo(this.value);
  }

  add(valueToAdd) {
    this.value = this.value + valueToAdd;
  }

  subtract(valueToSubtract) {
    this.value = this.value - valueToSubtract;
  }

  multiply(valueToMultiply) {
    this.value = this.value * valueToMultiply;
  }

  divide(valueToDivide) {
    this.value = this.value / valueToDivide;
  }
}

class AddCommand {
  constructor(valueToAdd) {
    this.valueToAdd = valueToAdd;
  }

  execute(currentValue) {
    return currentValue + this.valueToAdd;
  }

  undo(currentValue) {
    return currentValue - this.valueToAdd;
  }
}

class SubtractCommand {
  constructor(valueToSubtract) {
    this.valueToSubtract = valueToSubtract;
  }

  execute(currentValue) {
    return currentValue - this.valueToSubtract;
  }

  undo(currentValue) {
    return currentValue + this.valueToSubtract;
  }
}

class MultiplyCommand {
  constructor(valueToMultiply) {
    this.valueToMultiply = valueToMultiply;
  }

  execute(currentValue) {
    return currentValue * this.valueToMultiply;
  }

  undo(currentValue) {
    return currentValue / this.valueToMultiply;
  }
}

class DivideCommand {
  constructor(valueToDivide) {
    this.valueToDivide = valueToDivide;
  }

  execute(currentValue) {
    return currentValue / this.valueToDivide;
  }

  undo(currentValue) {
    return currentValue * this.valueToDivide;
  }
}

const calculator = new Calculator();

calculator.executeCommand(new AddCommand(10));
calculator.executeCommand(new MultiplyCommand(2));
console.log(calculator.value); // 20
calculator.undo();
console.log(calculator.value); // 10

命令模式的思想比较有意思,将数据和操作封装,实现上在 js 中很简单,我们甚至也不需要 class ,直接通过字面量对象传递也可以。

但实际开发中目前还没用到过,此处留坑。