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

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

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

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

1class Calculator {
2  constructor() {
3    this.value = 0
4  }
5
6  add(valueToAdd) {
7    this.value = this.value + valueToAdd
8  }
9
10  subtract(valueToSubtract) {
11    this.value = this.value - valueToSubtract
12  }
13
14  multiply(valueToMultiply) {
15    this.value = this.value * valueToMultiply
16  }
17
18  divide(valueToDivide) {
19    this.value = this.value / valueToDivide
20  }
21}
22
23const calculator = new Calculator()
24calculator.add(10)
25console.log(calculator.value) // 10
26calculator.divide(2)
27console.log(calculator.value) // 5

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

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

1class Calculator {
2  constructor() {
3    this.value = 0
4    this.history = []
5  }
6
7  executeCommand(command) {
8    this.value = command.execute(this.value)
9    this.history.push(command)
10  }
11
12  undo() {
13    const command = this.history.pop()
14    this.value = command.undo(this.value)
15  }
16
17  add(valueToAdd) {
18    this.value = this.value + valueToAdd
19  }
20
21  subtract(valueToSubtract) {
22    this.value = this.value - valueToSubtract
23  }
24
25  multiply(valueToMultiply) {
26    this.value = this.value * valueToMultiply
27  }
28
29  divide(valueToDivide) {
30    this.value = this.value / valueToDivide
31  }
32}
33
34class AddCommand {
35  constructor(valueToAdd) {
36    this.valueToAdd = valueToAdd
37  }
38
39  execute(currentValue) {
40    return currentValue + this.valueToAdd
41  }
42
43  undo(currentValue) {
44    return currentValue - this.valueToAdd
45  }
46}
47
48class SubtractCommand {
49  constructor(valueToSubtract) {
50    this.valueToSubtract = valueToSubtract
51  }
52
53  execute(currentValue) {
54    return currentValue - this.valueToSubtract
55  }
56
57  undo(currentValue) {
58    return currentValue + this.valueToSubtract
59  }
60}
61
62class MultiplyCommand {
63  constructor(valueToMultiply) {
64    this.valueToMultiply = valueToMultiply
65  }
66
67  execute(currentValue) {
68    return currentValue * this.valueToMultiply
69  }
70
71  undo(currentValue) {
72    return currentValue / this.valueToMultiply
73  }
74}
75
76class DivideCommand {
77  constructor(valueToDivide) {
78    this.valueToDivide = valueToDivide
79  }
80
81  execute(currentValue) {
82    return currentValue / this.valueToDivide
83  }
84
85  undo(currentValue) {
86    return currentValue * this.valueToDivide
87  }
88}
89
90const calculator = new Calculator()
91
92calculator.executeCommand(new AddCommand(10))
93calculator.executeCommand(new MultiplyCommand(2))
94console.log(calculator.value) // 20
95calculator.undo()
96console.log(calculator.value) // 10

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

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