Command(命令)
一、意图
将一个请求封装为一个对象,从而使得可以用不同的请求对客户进行参数化;对请求排队或记录请求口志,以及支持可撤销的操作。
二、结构
命令模式的结构图如图7-39所示。
其中:
• Command声明执行操作的接口。
• ConcreteCommand将一个接收者对象绑定于一个动作;调用接收者相应的操作,以实现 Execute。
• Client创建一个具体命令对象并设定它的接收者。
• Invoker要求该命令执行这个请求。
• Receiver知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。
三、适用性
Command模式适用于:
• 抽象出待执行的动作以参数化某对象。Command模式是过程语言中的回调(Callback) 机制的一个而向对象的替代品。
• 在不同的时刻指定、排列和执行请求。一个Command对象可以有一个与初始请求无关的生存期。如果一个请求的接收者可用一种与地址空间无关的方式表达,那么就可以将负责该请求的命令对象传递给另一个不同的进程并在那儿实现该请求。
• 支持取消操作。Command的Execute操作可在实施操作前将状态存储起来,在取消操作时这个状态用来消除该操作的影响。Command接口必须添加一个Unexecute操作, 该操作取消上一次Execute调用的效果。执行的命令被存储在一个历史列表中。可通过向后和向前遍历这一列表并分别调用Unexecute和Execute来实现重数不限的“取消” 和“重做”。
• 支持修改日志。这样当系统崩溃时,这些修改可以被重做一遍。在Command接口中添加装载操作和存储操作,可以用来保持变动的一个一致的修改口志。从崩溃中恢复的过程包括从磁盘中重新读入记录下来的命令并用Execute操作重新执行它们。
•用构建在原语操作上的高层操作构造一个系统。这样一种结构在支持事务 (Transaction)的信息系统中很常见。Command模式提供了对事务进行建模的方法。 Conmiand有一个公共接口,使得可以用同一种方式调用所有的事务,同时使用该模式也易于添加新事务以扩展系统。
四、实现
某灯具厂商欲生产一个灯具遥控器,该遥控器具有 7 个可编程的插槽,每个插槽都有开关按钮,对应着一个不同的灯。利用该遥控器能够统一控制房间中该厂商所有品牌灯具的开关,现采用 Command(命令)模式实现该遥控器的软件部分。Command 模式的类图如图6-1 所示。
首先 创建灯这个类
。
class Light {
String name;
public Light() {}
public Light(String name) {
this.name=name;
}
public void on() { // 开灯
System.out.println(name+":开灯");
}
public void off(){ // 关灯
System.out.println(name+":关灯");
}
}
然后 创建命令结构并且用开灯命令和关灯命令分别来实现
。
interface Command{
public void execute();
}
class LightOnCommand implements Command { // 开灯命令
Light light;
public LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.on();
}
}
class LightOffCommand implements Command { // 关灯命令
Light light;
public LightOffCommand(Light light) {
this.light = light;
}
public void execute() {
light.off();
}
}
其次 创建遥控器这个类
。
class RemoteControl { // 遥控器
Command[] onCommands = new Command[7];
Command[] offCommands = new Command[7];
public RemoteControl() {}
public void setCommand(int slot, Command onCommand, Command offCommand){
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
public void onButtonWasPushed(int slot) {
onCommands[slot].execute();
}
public void offButtonWasPushed(int slot) {
offCommands[slot].execute();
}
}
最后 测试一下
。
public class CommandPattern {
public static void main(String[] args) {
// TODO Auto-generated method stub
RemoteControl remoteControl = new RemoteControl();
Light livingRoomLight = new Light("Living Room");
Light kitchenLight = new Light("kitchen");
LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight);
LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight);
LightOnCommand kitchenLightOn = new LightOnCommand(kitchenLight);
LightOffCommand kitchenLightOff = new LightOffCommand(kitchenLight);
remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);
remoteControl.setCommand(1, kitchenLightOn, kitchenLightOff);
remoteControl.onButtonWasPushed(0);
remoteControl.offButtonWasPushed(0);
remoteControl.onButtonWasPushed(1);
remoteControl.offButtonWasPushed(1);
}
}
运行结果: