[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"));
相关推荐
金池尽干30 分钟前
设计模式之——观察者模式
观察者模式·设计模式
别拿曾经看以后~36 分钟前
【el-form】记一例好用的el-input输入框回车调接口和el-button按钮防重点击
javascript·vue.js·elementui
川石课堂软件测试42 分钟前
性能测试|docker容器下搭建JMeter+Grafana+Influxdb监控可视化平台
运维·javascript·深度学习·jmeter·docker·容器·grafana
也无晴也无风雨43 分钟前
代码中的设计模式-策略模式
设计模式·bash·策略模式
JerryXZR1 小时前
前端开发中ES6的技术细节二
前端·javascript·es6
problc1 小时前
Flutter中文字体设置指南:打造个性化的应用体验
android·javascript·flutter
Gavin_9151 小时前
【JavaScript】模块化开发
前端·javascript·vue.js
懒大王爱吃狼2 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
待磨的钝刨3 小时前
【格式化查看JSON文件】coco的json文件内容都在一行如何按照json格式查看
开发语言·javascript·json
前端青山8 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js