将命令模式类比到日常生活中,可以想象一个餐厅的运作过程。在这个类比中,顾客点菜的过程就像是发出一个命令,而厨师则是执行命令的接收者。
角色类比
- 顾客(Client):下达命令。他们决定要什么菜,并通知服务员。
- 服务员(Invoker):接收命令,并传递给厨师。服务员不需要知道菜怎么做,他们只负责确保命令被正确记录并传达给厨师。
- 命令单(Command):服务员记录顾客点的菜的纸条或电子设备。每个命令单都会详细说明所需的菜品和顾客的特殊要求。
- 厨师(Receiver):执行命令。他们根据命令单上的内容准备菜品。
- 菜品(Action):命令的结果,也就是厨师根据命令单准备的食物。
过程类比
想象你走进一家餐厅,坐下后开始点菜(这是你发出的命令)。服务员(Invoker)将你的选择写在命令单上或输入到电子系统中。这个命令单就是一个具体的命令(ConcreteCommand),它包含了所有必要的信息,以便厨师(Receiver)能够准备菜品。
当服务员将命令传递给厨房后,厨师开始根据命令单上的指示准备食物。在这个过程中,即使服务员不在厨房,厨师也能独立完成任务,因为他们有明确的指示。
在某些情况下,顾客可能会改变主意,比如取消或更改订单。如果命令尚未执行,服务员可以简单地撤销或修改命令单上的内容,这类似于命令模式中的撤销(undo)操作。
基于餐厅类比的命令模式,我们可以将其转换成代码。以下是一个简化的Java示例,展示了如何实现命令模式:
// Command接口
public interface OrderCommand {
void execute();
}
// ConcreteCommand:制作汉堡的命令
public class BurgerOrder implements OrderCommand {
private Chef chef;
public BurgerOrder(Chef chef) {
this.chef = chef;
}
@Override
public void execute() {
chef.cookBurger();
}
}
// ConcreteCommand:制作沙拉的命令
public class SaladOrder implements OrderCommand {
private Chef chef;
public SaladOrder(Chef chef) {
this.chef = chef;
}
@Override
public void execute() {
chef.makeSalad();
}
}
// Receiver:厨师
public class Chef {
public void cookBurger() {
System.out.println("The chef is cooking a burger.");
}
public void makeSalad() {
System.out.println("The chef is preparing a salad.");
}
}
// Invoker:服务员
public class Waiter {
private OrderCommand order;
public void takeOrder(OrderCommand order) {
this.order = order;
}
public void placeOrder() {
System.out.println("Waiter is placing the order to the chef.");
order.execute();
}
}
// Client:顾客
public class Customer {
public static void main(String[] args) {
Chef chef = new Chef();
Waiter waiter = new Waiter();
OrderCommand burgerOrder = new BurgerOrder(chef);
OrderCommand saladOrder = new SaladOrder(chef);
// 顾客点汉堡
waiter.takeOrder(burgerOrder);
waiter.placeOrder(); // Output: "Waiter is placing the order to the chef."
// "The chef is cooking a burger."
// 顾客点沙拉
waiter.takeOrder(saladOrder);
waiter.placeOrder(); // Output: "Waiter is placing the order to the chef."
// "The chef is preparing a salad."
}
}
在这个示例中,OrderCommand
接口定义了所有命令的共同接口。BurgerOrder
和SaladOrder
是具体的命令,它们实现了OrderCommand
接口,并在execute
方法中调用Chef
的对应方法。
Chef
类是命令的接收者,它知道如何执行与制作特定食物相关的操作。Waiter
是调用者,它接收顾客的命令并将其传递给厨师。
最后,客户端代码中的Customer
类创建了一个厨师、一个服务员和一些具体的命令对象。顾客通过服务员下达命令,服务员将命令传递给厨师执行。这样,顾客、服务员和厨师之间的关系就被解耦,每个角色只需关注自己的职责。
设计模式的体现
这个类比展示了命令模式的几个关键特点:
- 解耦:服务员(Invoker)和厨师(Receiver)之间是解耦的。服务员不需要知道菜是如何准备的,而厨师不需要知道顾客是谁。
- 可扩展性:餐厅可以轻松地引入新的菜品,这就像在软件中添加新的
ConcreteCommand
一样简单。只要厨师知道如何准备这些新菜品,服务员就可以开始接受新的订单。 - 灵活性:如果顾客改变主意,只需修改或撤销命令单即可。在软件中,命令模式允许我们通过调用
undo
方法来撤销操作。
总结
通过这个类比,我们可以看到命令模式如何将发出请求的客户端与接收和执行请求的代码分离开来。这种分离带来了高度的灵活性和可扩展性,同时使得请求的发出、记录、排队和撤销变得简单。在软件设计中,这种模式允许我们编写更加模块化和可维护的代码。