1 意图
将一个请求封装为一个对象,从而使得可以用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
2 结构
- Command 声明执行操作的接口。
- ConcreteCommand 将一个接收者对象绑定于一个动作;调用接收者相应的操作,以实现 Execute。
- Client 创建一个具体命令对象并设定它的接收者。
- Invoker 要求该命令执行这个请求。
- Receiver 知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。
3 适用性
Command 模式适用于:
-
抽象出待执行的动作以参数化某对象。Command 模式是过程语言中的回调(Callback)机制的一个面向对象的替代品。
-
在不同的时刻指定、排列和执行请求。一个Command 对象可以有一个与初始请求无关的生存期。如果一个请求的接收者可用一种与地址空间无关的方式表达,那么就可以将负责该请求的命令对象传递给另一个不同的进程并在那儿实现该请求。
-
支持取消操作。Command 的Execute 操作可在实施操作前将状态存储起来,在取消操作时这个状态用来消除该操作的影响。Command 接口必须添加一个 Unexecute 操作,该操作取消上一次 Execute 调用的效果。执行的命令被存储在一个历史列表中。可通过向后和向前遍历这一列表并分别调用Unexecute和Execute来实现重数不限的“取消和“重做”。
-
支持修改日志。这样当系统崩溃时,这些修改可以被重做一遍。在Command 接口中添加装载操作和存储操作,可以用来保持变动的一个一致的修改日志。从崩溃中恢复的过程包括从磁盘中重新读入记录下来的命令并用 Execute 操作重新执行它们。
-
用构建在原语操作上的高层操作构造一个系统。这样一种结构在支持事务(Transaction)的信息系统中很常见。Command 模式提供了对事务进行建模的方法。Command 有一个公共接口,使得可以用同一种方式调用所有的事务,同时使用该模式也易于添加新事务以扩展系统。
实例
1 开或关闭灯光
命令模式(Command Pattern)是一种行为设计模式,它将请求封装成对象,从而可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。下面我将通过一个简单的例子来解释命令模式的应用,这个例子涉及到家庭自动化系统,比如使用遥控器控制家里的灯。
场景描述
假设我们有一个家庭自动化系统,其中包含一个遥控器,可以用来打开或关闭家里的灯光。为了实现这一功能,我们可以使用命令模式来设计。
参与者
- Command (命令接口) - 定义执行操作的声明。
- ConcreteCommand (具体命令类) - 实现了 Command 接口,负责调用接收者的相应操作。
- Receiver (接收者) - 知道如何实施与执行一个请求相关的操作。任何类都可以作为接收者,具体取决于应用程序。
- Invoker (调用者) - 要求该命令执行这个请求。
- Client (客户端) - 创建一个具体命令对象并设定它的接收者。
示例代码
1. 命令接口 (Command)
public interface Command {void execute();
}
2. 具体命令类 (ConcreteCommand)
public class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOn();}
}public class LightOffCommand implements Command {private Light light;public LightOffCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOff();}
}
3. 接收者 (Receiver)
public class Light {public void turnOn() {System.out.println("The light is on.");}public void turnOff() {System.out.println("The light is off.");}
}
4. 调用者 (Invoker)
public class RemoteControl {private Command command;public void setCommand(Command command) {this.command = command;}public void pressButton() {command.execute();}
}
5. 客户端 (Client)
public class Client {public static void main(String[] args) {// 创建接收者对象Light livingRoomLight = new Light();// 创建命令对象Command turnOnLivingRoomLight = new LightOnCommand(livingRoomLight);Command turnOffLivingRoomLight = new LightOffCommand(livingRoomLight);// 创建调用者对象RemoteControl remoteControl = new RemoteControl();// 设置命令remoteControl.setCommand(turnOnLivingRoomLight);remoteControl.pressButton(); // 输出: The light is on.remoteControl.setCommand(turnOffLivingRoomLight);remoteControl.pressButton(); // 输出: The light is off.}
}
在这个例子中,RemoteControl
类充当调用者,它不知道具体的命令是什么,只知道调用 execute()
方法。LightOnCommand
和 LightOffCommand
是具体命令,它们实现了 Command
接口,并且知道如何让 Light
对象执行相应的操作。这样设计的好处是增加了灵活性和解耦,允许在运行时动态地改变命令,或者添加新的命令而不需要修改现有的代码。
2 订单处理
命令模式在电子商务(E-commerce)和办公自动化(OA)系统中也有广泛的应用。这里我将以一个电商购物车的订单处理为例,展示如何使用命令模式来优化订单管理流程。
场景描述
在一个电商平台上,用户可以将商品添加到购物车,然后提交订单。平台需要处理多种类型的订单,例如普通订单、促销订单等。此外,还需要支持订单的取消和恢复功能。
参与者
- OrderCommand (命令接口) - 定义执行订单操作的方法。
- ConcreteOrderCommand (具体命令类) - 实现 OrderCommand 接口,负责调用订单服务的具体操作。
- OrderService (接收者) - 执行实际的订单处理逻辑。
- OrderProcessor (调用者) - 请求命令执行。
- Client (客户端) - 创建命令对象并设置命令处理器。
示例代码
1. 命令接口 (OrderCommand)
public interface OrderCommand {void execute();void undo();
}
2. 具体命令类 (ConcreteOrderCommand)
public class PlaceOrderCommand implements OrderCommand {private OrderService orderService;private String orderId;public PlaceOrderCommand(OrderService orderService, String orderId) {this.orderService = orderService;this.orderId = orderId;}@Overridepublic void execute() {orderService.placeOrder(orderId);}@Overridepublic void undo() {orderService.cancelOrder(orderId);}
}public class CancelOrderCommand implements OrderCommand {private OrderService orderService;private String orderId;public CancelOrderCommand(OrderService orderService, String orderId) {this.orderService = orderService;this.orderId = orderId;}@Overridepublic void execute() {orderService.cancelOrder(orderId);}@Overridepublic void undo() {orderService.restoreOrder(orderId);}
}
3. 接收者 (OrderService)
public class OrderService {public void placeOrder(String orderId) {System.out.println("Placing order: " + orderId);}public void cancelOrder(String orderId) {System.out.println("Cancelling order: " + orderId);}public void restoreOrder(String orderId) {System.out.println("Restoring order: " + orderId);}
}
4. 调用者 (OrderProcessor)
import java.util.ArrayList;
import java.util.List;public class OrderProcessor {private List<OrderCommand> commands = new ArrayList<>();public void addCommand(OrderCommand command) {commands.add(command);}public void processCommands() {for (OrderCommand command : commands) {command.execute();}commands.clear();}public void undoLastCommand() {if (!commands.isEmpty()) {OrderCommand lastCommand = commands.remove(commands.size() - 1);lastCommand.undo();}}
}
5. 客户端 (Client)
public class Client {public static void main(String[] args) {// 创建接收者对象OrderService orderService = new OrderService();// 创建命令对象OrderCommand placeOrderCmd = new PlaceOrderCommand(orderService, "12345");OrderCommand cancelOrderCmd = new CancelOrderCommand(orderService, "12345");// 创建调用者对象OrderProcessor orderProcessor = new OrderProcessor();// 添加命令orderProcessor.addCommand(placeOrderCmd);orderProcessor.addCommand(cancelOrderCmd);// 处理命令orderProcessor.processCommands();// 撤销最后一个命令orderProcessor.undoLastCommand();}
}
在这个例子中,OrderProcessor
类作为调用者,负责管理和执行命令。PlaceOrderCommand
和 CancelOrderCommand
是具体命令,实现了 OrderCommand
接口,并且知道如何调用 OrderService
的具体方法来处理订单。这种设计不仅使代码更加模块化和灵活,还支持命令的撤销和恢复功能,非常适合处理复杂的业务流程。