命令模式的定义
命令模式将“请求”封装成对象,以便使用不同的请求、队列、或者日志来参数化其它对象。命令模式也支持可撤销的操作。
场景
家电自动化遥控器
场景描述
遥控器具有7个可编程的插槽,其中每个插槽都可以指定到不同的家电装置(如电灯、风扇、热水器、音响设备、等等),并且每个插槽都有对应的开关按钮。遥控器还具有一个整体的撤销按钮。现在,需要设计一组控制遥控器的API,让每个插槽都能够控制一个或一组装置(备注,需要能够控制目前的设备和任务未来可能出现的设备)。
下图是一些已知家电设备厂商的API:
方案
使用命令模式将动作的请求者和动作的执行者对象中解藕。请求者为遥控器,执行者对象是家电设备,利用命令对象,把请求(例如,打开电灯)封装成一个特定对象(例如,客厅电灯对象)。所以,如果每个按钮都存储一个命令对象,那么当按钮被按下的时候,就可以请命令对象做相关的工作。遥控器并不需要知道工作内容是什么,只要有一个命令对象能和正确的对象沟通,把事情做好就可以了。这样,遥控器和电灯对象就解藕了。
1 2 3 4
| public interface Command { public void execute(); public void undo(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public class LightOnCommand implements Command { Light light;
public LightOnCommand(Light light) { this.light = light; }
public void execute() { light.on(); }
public void undo() { light.off(); } }
public class LightOffCommand implements Command { Light light;
public LightOffCommand(Light light) { this.light = light; }
public void execute() { light.off(); } public void undo() { light.on(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| public class RemoteControl { Command[] onCommands; Command[] offCommands; Command undoCommand;
public RemoteControl() { onCommands = new Command[7]; offCommands = new Command[7]; Command noCommand = new NoCommand(); for (int i = 0; i < 7; i++) { onCommands[i] = noCommand; offCommands[i] = noCommand; } undoCommand = noCommand; }
public void setCommand(int slot, Command onCommand, Command offCommand) { onCommands[slot] = onCommand; offCommands[slot] = offCommand; } public void onButtonWasPushed(int slot) { onCommands[slot].execute(); undoCommand = onCommands[slot]; } public void offButtonWasPushed(int slot) { offCommands[slot].execute(); undoCommand = onCommands[slot]; }
public void undoButtonWasPushed() { undoCommand.undo(); }
public String toString() { StringBuffer stringBuff = new StringBuffer(); stringBuff.append("\n------ Remote Control -------\n"); for (int i = 0; i < onCommands.length; i++) { stringBuff.append("[slot " + i + "] " + onCommands[i].getClass().getName() + " " + offCommands[i].getClass().getName() + "\n"); } return stringBuff.toString(); } }
|
方案的更进一步
利用宏命令,实现一个按钮同时控制多个灯光、音箱、电视、DVD、热水器的功能。
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class MacroCommand implements Command { Command[] commands;
public MacroCommand(Command[] commands) { this.commands = commands; }
public void execute() { for (int i = 0; i < commands.length; i++) { commands[i].execute(); } } }
|