使用命令模式,可以将执行某个任务的对象与调用该方法的对象解耦。
假设有一个外卖配送平台。用户可以下单、跟踪和取消订单。
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
方法。直接使用这些方法将是完全可行的。
但是,直接在 manager
实例上调用方法也有缺点。我们可能会决定稍后重命名某些方法,或者改变某些方法的功能。
假设现在将其重命名为 addOrder
,而不是 placeOrder
,这意味着我们必须确保代码库中的没有任何位置调用 placeOrder
方法,这种场景在大型应用程序中可能非常棘手。相反,我们希望将方法与 manager
对象解耦,并为每个命令创建单独的命令函数。
让我们重构 OrderManager
类:它不再具有 placeOrder
、 cancelOrder
和 trackOrder
方法,而是只有一个方法: execute
。该方法将执行它给出的任何命令。
class OrderManager {
constructor() {
this.orders = [];
}
execute(command, ...args) {
return command.execute(this.orders, ...args);
}
}
还需要为订单管理器创建三个 Command
:
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.`);
}
const manager = new OrderManager();
manager.execute(new PlaceOrderCommand("noodle", "1234"));
manager.execute(new TrackOrderCommand("1234"));
manager.execute(new CancelOrderCommand("1234"));
这些方法不再直接耦合到 OrderManager
实例,而是现在是独立的解耦函数,我们可以通过 OrderManager
方法调用它们。
优点
命令模式允许我们将方法从执行操作的对象中解耦。它能够更加灵活的控制,比如一些具有生命周期的命令,又或者需要在特定时间排队并执行的命令。
缺点
命令模式的用例非常有限,并且经常向应用程序添加不必要的样板。