Skip to content

命令模式

通过命令模式,我们可以将执行具体的任务的对象和调用该任务的对象解耦。

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

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

  placeOrder(order, id) {
    this.orders.push(id)
    // return `You have successfully ordered ${order} (${id})`;
    return `你已成功点单 ${order} (${id})`;
  }

  trackOrder(id) {
    // return `Your order ${id} will arrive in 20 minutes.`
    return `你的订单 ${id} 将在 20 分钟后送达。`
  }

  cancelOrder(id) {
    this.orders = this.orders.filter(order => order.id !== id)
    return `你已成功取消订单 ${id}`
    // return `You have canceled your order ${id}`
  }
}

OrderManager 类中,我们创建了 placeOrdertrackOrdercancelOrder 方法。它们在 JavaScript 中完全可用,并且可以直接调用。

javascript
const manager = new OrderManager();

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

然而,在 manager 实例上直接调用方法也是有缺点的。例如后面我们可能会修改某些方法名,或者更改某一些方法的功能。

假设我们想要把 placeOrder 重命名为 addOrder,这意味着我们在项目中的任何位置都不能再调用 placeOrder。这在大型的程序中将会变得非常棘手。所以我们需要将方法和 manager 对象解耦,为每个命令创建单独的命令函数。

我们来重构 OrderManager 类。我们不再需要 placeOrder, cancelOrdertrackOrder 方法,取而代之的,我们只需要一个方法 excute。这个方法将会执行任何传入的命令。

任何命令都应该可以访问 OrderManager 下的 order,我们将把命令作为第一个参数传入 excute 方法。

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

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

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

  • PlaceOrderCommand
  • CancelOrderCommand
  • TrackOrderCommand
javascript
class Command {
  constructor(execute) {
    this.execute = execute;
  }
}

function PlaceOrderCommand(order, id) {
  return new Command((orders) => {
    orders.push(id);
    // return `You have successfully ordered ${order} (${id})`;
    return `你已经成功点单 ${order} (${id})`;
  });
}

function CancelOrderCommand(id) {
  return new Command((orders) => {
    orders = orders.filter((order) => order.id !== id);
    return `你成功取消了你的订单 ${id}`;
    // return `You have canceled your order ${id}`;
  });
}

function TrackOrderCommand(id) {
  return new Command(() => `你的订单 ${id} 将在 20 分钟内送达.`);
  // return new Command(() => `Your order ${id} will arrive in 20 minutes.`);
}

太棒了!这些方法不再直接与 OrderManager 实例耦合,而是变成了独立的、解耦的函数,我们可以通过 OrderManager 上的 execute 方法调用它们。

在演练场中查看代码

优点

命令模式使得方法和调用方法的实例解耦。当执行的命令具有一定的生命周期,或者需要在队列中执行,抑或是在特定的时间执行,命令模式可以让你对其拥有更多的控制权。

Cons

命令模式的用例收到很大的限制,并且经常会给应用程序添加不必要的样板代码。

引用

最后更新于: