使用命令模式 ,可以将执行特定任务的对象与调用该方法的对象分离。假设有一个在线送餐平台。用户可以下订单、跟踪订单和取消订单。
javascript
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
方法。直接使用这些方法将是完全有效的 JavaScript!
javascript
const manager = new OrderManager();
manager.placeOrder("Pad Thai", "1234");
manager.trackOrder("1234");
manager.cancelOrder("1234");
但是,直接在manager
实例上调用这些方法也有缺点。以后可能会决定重命名某些方法,或者方法的功能发生变化。
假设现在不将其命名为 placeOrder
,而是将其重命名为 addOrder
!这意味着必须确保不会在代码库中的任何位置调用 placeOrder
方法,这在大型应用程序中可能非常棘手。相反,希望将方法与 manager
对象分离,并为每个命令创建单独的命令函数!
让我们重构 OrderManager
类:它不再有 placeOrder
、cancelOrder
和 trackOrder
方法,而是只有一个方法:execute
。此方法将执行它给出的任何命令。
每个命令都应该有权访问管理器orders
,我们将将其作为其第一个参数传递。
javascript
class OrderManager {
constructor() {
this.orders = [];
}
execute(command, ...args) {
return command.execute(this.orders, ...args);
}
}
这里需要为订单管理器创建三个Command
:
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})`;
});
}
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
上可用的 execute
方法调用它们。
优点
命令模式允许我们将方法与执行操作的对象解耦。如果您正在处理具有一定生命周期的命令,或者应该在特定时间排队和执行的命令,那么它可以使您获得更大的控制权。
缺点
命令模式的使用情况相当有限,并且经常为应用程序添加不必要的样板代码。