设计模式
命令模式
使用 **命令模式**,我们可以 *解耦* 执行特定任务的对象和调用该方法的对象。
假设我们有一个在线食品外送平台。用户可以下单、跟踪和取消订单。
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 中完全有效!
const manager = new OrderManager();
manager.placeOrder("Pad Thai", "1234");
manager.trackOrder("1234");
manager.cancelOrder("1234");
但是,直接在 manager
实例上调用方法有缺点。我们可能会在稍后决定重命名某些方法,或者方法的功能会发生改变。
假设我们不再将 placeOrder
称为 placeOrder
,而是将其重命名为 addOrder
!这意味着我们必须确保在代码库中任何地方都不调用 placeOrder
方法,这在大型应用程序中可能非常棘手。相反,我们希望将方法与 manager
对象解耦,并为每个命令创建单独的命令函数!
让我们重构 OrderManager
类:它不再包含 placeOrder
、cancelOrder
和 trackOrder
方法,而只有一个方法:execute
。此方法将执行它收到的任何命令。
每个命令都应该可以访问 manager
的 orders
,我们将其作为第一个参数传递给它。
class OrderManager {
constructor() {
this.orders = [];
}
execute(command, ...args) {
return command.execute(this.orders, ...args);
}
}
我们需要为订单管理器创建三个 Command
。
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
上可用的 execute
方法调用它们。
1class OrderManager {2 constructor() {3 this.orders = [];4 }56 execute(command, ...args) {7 return command.execute(this.orders, ...args);8 }9}1011class Command {12 constructor(execute) {13 this.execute = execute;14 }15}1617function PlaceOrderCommand(order, id) {18 return new Command(orders => {19 orders.push(id);20 console.log(`You have successfully ordered ${order} (${id})`);21 });22}2324function CancelOrderCommand(id) {25 return new Command(orders => {26 orders = orders.filter(order => order.id !== id);27 console.log(`You have canceled your order ${id}`);28 });29}3031function TrackOrderCommand(id) {32 return new Command(() =>33 console.log(`Your order ${id} will arrive in 20 minutes.`)34 );35}3637const manager = new OrderManager();3839manager.execute(new PlaceOrderCommand("Pad Thai", "1234"));40manager.execute(new TrackOrderCommand("1234"));41manager.execute(new CancelOrderCommand("1234"));
优点
命令模式使我们能够将方法与执行该操作的对象解耦。如果您处理具有特定生命周期的命令,或者应该在特定时间排队和执行的命令,它将为您提供更多控制权。
缺点
命令模式的用例非常有限,并且通常会为应用程序增加不必要的样板代码。