Appearance
命令模式
通过命令模式,我们可以将执行具体的任务的对象和调用该任务的对象解耦。
假设我们有一个在线视频配送平台,用户可以下单、跟踪和取消订单。
javascript
class OrderManager() {
constructor() {
this.orders = []
}
placeOrder(order, id) {
this.orders.push(id)
// return `You have successfully ordered ${order} (${id})`;
return `你已成功点单 ${order} (${id})`;
}
trackOrder(id) {
// return `Your order ${id} will arrive in 20 minutes.`
return `你的订单 ${id} 将在 20 分钟后送达。`
}
cancelOrder(id) {
this.orders = this.orders.filter(order => order.id !== id)
return `你已成功取消订单 ${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
方法,取而代之的,我们只需要一个方法 excute
。这个方法将会执行任何传入的命令。
任何命令都应该可以访问 OrderManager
下的 order
,我们将把命令作为第一个参数传入 excute
方法。
javascript
class OrderManager {
constructor() {
this.orders = [];
}
execute(command, ...args) {
return command.execute(this.orders, ...args);
}
}
我们需要为订单管理器创建三个 命令 Commands
:
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})`;
return `你已经成功点单 ${order} (${id})`;
});
}
function CancelOrderCommand(id) {
return new Command((orders) => {
orders = orders.filter((order) => order.id !== id);
return `你成功取消了你的订单 ${id}`;
// return `You have canceled your order ${id}`;
});
}
function TrackOrderCommand(id) {
return new Command(() => `你的订单 ${id} 将在 20 分钟内送达.`);
// return new Command(() => `Your order ${id} will arrive in 20 minutes.`);
}
太棒了!这些方法不再直接与 OrderManager
实例耦合,而是变成了独立的、解耦的函数,我们可以通过 OrderManager
上的 execute
方法调用它们。
优点
命令模式使得方法和调用方法的实例解耦。当执行的命令具有一定的生命周期,或者需要在队列中执行,抑或是在特定的时间执行,命令模式可以让你对其拥有更多的控制权。
Cons
命令模式的用例收到很大的限制,并且经常会给应用程序添加不必要的样板代码。
引用
- 命令设计模式 Command Design Pattern - SourceMaking
- 命令模式 Command Pattern - Refactoring Guru
- 命令模式 Command Pattern - Carlos Caballero