跳至主要內容

命令模式

patternsreadingdesign patternvanillacommand-pattern大约 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 类中,我们可以直接访问 placeOrdertrackOrdercancelOrder 方法。

const manager = new OrderManager()

manager.placeOrder('Pad Thai', '1234')
manager.trackOrder('1234')
manager.cancelOrder('1234')

不过,直接在 manager 实例上调用方法也有缺点。我们可能会决定重新命名某些方法,或者方法的功能发生变化。

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

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

让我们重构 OrderManager 类:它将不再有 placeOrdercancelOrdertrackOrder 方法,而只有一个方法:execute。该方法将执行给定的任何命令。

每个命令都应能访问 OrderManagerorders,我们将把它作为第一个参数传递。

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

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

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

  • PlaceOrderCommand
  • CancelOrderCommand
  • TrackOrderCommand
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'))

优点

命令模式允许我们将方法与执行操作的对象解耦。如果您要处理的命令有一定的生命周期,或者命令需要排队并在特定时间执行,那么它能让您获得更多控制权。

缺点

命令模式的用例非常有限,而且往往会给应用程序增加不必要的模板。

参考