命令模式

使用命令模式,我们可以将执行特定任务的对象与调用该方法的对象解耦。


订单管理案例

假设我们有一个在线食品配送平台。 用户可以下订单、跟踪订单和取消订单。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20

class OrderManager() {
  constructor() {
    this.orders = []
  }

  placeOrder(order, id) {
    this.orders.push(id)
    return `您已成功订购 ${order} (${id})`;
  }

  trackOrder(id) {
    return `您的订单 ${id} 将在 20 分钟内送达。`
  }

  cancelOrder(id) {
    this.orders = this.orders.filter(order => order.id !== id)
    return `您已取消订单 ${id}`
  }
}

OrderManager 类中,我们可以访问 placeOrdertrackOrdercancelOrder 方法。

const manager = new OrderManager();

manager.placeOrder("Pad Thai", "1234");
manager.trackOrder("1234");
manager.cancelOrder("1234");

但是,直接在管理器实例上调用方法也有缺点。

可能会发生我们决定稍后重命名某些方法,或者方法的功能发生变化的情况。

假设我们现在将其重命名为 addOrder,而不是将其称为 placeOrder
这意味着我们必须确保不会在代码库的任何地方调用 placeOrder 方法,这在较大的应用程序中可能非常棘手。

将方法与管理器对象分离 – 命令函数

相反,我们希望将方法管理器对象分离,并为每个命令创建单独的命令函数!

让我们重构 OrderManager 类:它没有 placeOrder、cancelOrder 和 trackOrder 方法,而是只有一个方法:execute
此方法将执行它给出的任何命令。

每个命令都应该可以访问 OrderManagerorders,我们将其作为它的第一个参数传递。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10

class OrderManager {
  constructor() {
    this.orders = [];
  }

  execute(command, ...args) {
    return command.execute(this.orders, ...args);
  }
}

我们需要为订单管理器创建三个命令:

  • PlaceOrderCommand
  • CancelOrderCommand
  • TrackOrderCommand
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

class OrderManager {
  constructor() {
    this.orders = [];
  }

  execute(command, ...args) {
    return command.execute(this.orders, ...args);
  }
}

class Command {
  constructor(execute) {
    this.execute = execute;
  }
}

function PlaceOrderCommand(order, id) {
  return new Command(orders => {
    orders.push(id);
    return `您已成功订购 ${order} (${id})`;
  });
}

function CancelOrderCommand(id) {
  return new Command(orders => {
    orders = orders.filter(order => order.id !== id);
    return `您已取消订单 ${id}`;
  });
}

function TrackOrderCommand(id) {
  return new Command(() => `您的订单 ${id} 将在 20 分钟内送达。`);
}

优点

命令模式允许我们将方法与执行操作的对象分离。

如果您正在处理具有特定生命周期的命令,或者应该在特定时间排队和执行的命令,它会给您更多的控制权。


缺点

命令模式的用例非常有限,并且经常向应用程序添加不必要的样板。


知识点

  • class
  • 递归
  • Array.prototype.push()
  • Array.prototype.filter()