命令模式
大约 2 分钟约 723 字
命令模式
通过命令模式,我们可以将执行特定任务的对象与调用方法的对象 解耦。
假设我们有一个在线食品配送平台。用户可以下单、跟踪和取消订单。
class OrderManager() {
  constructor() {
    this.orders = []
  }
  placeOrder(order, id) {
    this.orders.push(id)
    return `You have successfully ordered ${order} (${id})`;
  }
  trackOrder(id) {
    return `Your order ${id} will arrive in 20 minutes.`
  }
  cancelOrder(id) {
    this.orders = this.orders.filter(order => order.id !== id)
    return `You have canceled your order ${id}`
  }
}
在 OrderManager 类中,我们可以直接访问 placeOrder、trackOrder 和 cancelOrder 方法。
const manager = new OrderManager()
manager.placeOrder('Pad Thai', '1234')
manager.trackOrder('1234')
manager.cancelOrder('1234')
不过,直接在 manager 实例上调用方法也有缺点。我们可能会决定重新命名某些方法,或者方法的功能发生变化。
假设我们现在不调用 placeOrder,而是将其重命名为 addOrder!这意味着我们必须确保不在代码库的任何地方调用 placeOrder 方法,这在大型应用程序中可能会非常棘手。
相反,我们希望将这些方法与管理器对象分离,并为每个命令创建单独的命令函数!
让我们重构 OrderManager 类:它将不再有 placeOrder、cancelOrder 和 trackOrder 方法,而只有一个方法:execute。该方法将执行给定的任何命令。
每个命令都应能访问 OrderManager 的 orders,我们将把它作为第一个参数传递。
class OrderManager {
  constructor() {
    this.orders = []
  }
  execute(command, ...args) {
    return command.execute(this.orders, ...args)
  }
}
我们需要为订单管理器创建三个命令:
PlaceOrderCommandCancelOrderCommandTrackOrderCommand
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})`
  })
}
function CancelOrderCommand(id) {
  return new Command((orders) => {
    orders = orders.filter((order) => order.id !== id)
    return `You have canceled your order ${id}`
  })
}
function TrackOrderCommand(id) {
  return new Command(() => `Your order ${id} will arrive in 20 minutes.`)
}
完美!现在,这些方法不再直接与 OrderManager 实例耦合,而是成为独立的解耦函数,我们可以通过 OrderManager 上可用的执行方法来调用它们。
<p>打开调试控制台查看输出</p>
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)
    console.log(`You have successfully ordered ${order} (${id})`)
  })
}
function CancelOrderCommand(id) {
  return new Command((orders) => {
    orders = orders.filter((order) => order.id !== id)
    console.log(`You have canceled your order ${id}`)
  })
}
function TrackOrderCommand(id) {
  return new Command(() =>
    console.log(`Your order ${id} will arrive in 20 minutes.`)
  )
}
const manager = new OrderManager()
manager.execute(new PlaceOrderCommand('Pad Thai', '1234'))
manager.execute(new TrackOrderCommand('1234'))
manager.execute(new CancelOrderCommand('1234'))
优点
命令模式允许我们将方法与执行操作的对象解耦。如果您要处理的命令有一定的生命周期,或者命令需要排队并在特定时间执行,那么它能让您获得更多控制权。
缺点
命令模式的用例非常有限,而且往往会给应用程序增加不必要的模板。
参考
- Command Design Pattern - SourceMaking
 - Command Pattern - Refactoring Guru
 - Command Pattern - Carlos Caballero