[JS设计模式]Command Pattern

文章目录

With the Command Pattern , we can decouple objects that execute a certain task from the object that calls the method.

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

怎么理解 执行特定任务的对象 与 调用该方法的对象解耦?

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

举例说明

Let's say we have an online food delivery platform. Users can place, track, and cancel orders.

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

js 复制代码
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}`
  }
}

On the OrderManager class, we have access to the placeOrder , trackOrder and cancelOrder methods. It would be totally valid JavaScript to just use these methods directly!

在OrderManager类中,可以访问placeOrder、trackOrder和cancelOrder方法。直接使用这些方法将是完全有效的JavaScript !

js 复制代码
const manager = new OrderManager();

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

However, there are downsides to invoking the methods directly on the manager instance. It could happen that we decide to rename certain methods later on, or the functionality of the methods change.

直接通过manager实例调用这些方法也有潜在的问题。以后可能决定重命名某些方法,或者这些方法的功能发生了变化。

Say that instead of calling it placeOrder , we now rename it to addOrder ! This would mean that we would have to make sure that we don't call the placeOrder method anywhere in our codebase, which could be very tricky in larger applications. Instead, we want to decouple the methods from the manager object, and create separate command functions for each command!

现在我们将placeOrder重命名为addOrder。这意味着我们必须确保不在代码库的任何地方调用placeOrder方法,这在大型应用程序中可能非常棘手。相反,我们希望将方法与manager对象解耦,并为每个命令创建单独的命令函数!

Let's refactor the OrderManager class: instead of having the placeOrder , cancelOrder and trackOrder methods, it will have one single method: execute. This method will execute any command it's given.

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

Each command should have access to the orders of the manager, which we'll pass as its first argument.

每个命令都应该能够访问管理器的订单,我们将把它作为第一个参数传递给execute

js 复制代码
class OrderManager {
  constructor() {
    this.orders = [];
  }

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

We need to create three **Command**s for the order manager:

  • PlaceOrderCommand
  • CancelOrderCommand
  • TrackOrderCommand
js 复制代码
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.`);
}

Perfect! Instead of having the methods directly coupled to the OrderManager instance, they're now separate, decoupled functions that we can invoke through the execute method that's available on the OrderManager.

完美!不是将方法直接耦合到OrderManager实例,它们现在是分离的、解耦的函数,我们可以通过OrderManager上可用的execute方法调用它们。

优点

The command pattern allows us to decouple methods from the object that executes the operation. It gives you more control if you're dealing with commands that have a certain lifespan, or commands that should be queued and executed at specific times.

命令模式允许我们将方法与执行该方法的对象解耦。如果您正在处理具有特定生命周期的命令,或者应该在特定时间排队并执行的命令,那么它可以为您提供更多的控制。

缺点

The use cases for the command pattern are quite limited, and often adds unnecessary boilerplate to an application.

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

完整代码

js 复制代码
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"));
相关推荐
全栈前端老曹14 小时前
【前端地图】多地图平台适配方案——高德、百度、腾讯、Google Maps SDK 差异对比、封装统一地图接口
前端·javascript·百度·dubbo·wgs84·gcj-02·bd09
笑虾14 小时前
Win10 修改注册表 让鼠标悬停PNG上时 tip 始终显示分辨率
开发语言·javascript·ecmascript
雾岛听风69114 小时前
JavaScript基础语法速查手册
开发语言·前端·javascript
geovindu14 小时前
go:Template Method Pattern
开发语言·后端·设计模式·golang·模板方法模式
用户23678298016814 小时前
从零实现 GIF 制作工具:LZW 压缩与 Median Cut 色彩量化
前端·javascript
棉猴15 小时前
Python海龟绘图之绘制文本
javascript·python·html·write·turtle·海龟绘图·输出文本
钝挫力PROGRAMER15 小时前
贫血模型的改进
java·开发语言·设计模式·架构
Highcharts.js15 小时前
线形比赛积分增长或竞赛图|Highcharts企业图表代码示列
开发语言·前端·javascript·折线图·highcharts·竞赛图
让学习成为一种生活方式15 小时前
大肠杆菌合成扑热息痛--对乙酰氨基酚--文献精读227
开发语言·前端·javascript
多秋浮沉度华年16 小时前
electron 初始使用记录
javascript·arcgis·electron