命令模式
命令模式:将“请求”封装成对象,以便使用不同的请求,队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
定义命令模式:
类图
今天我们讲解命令模式的模型就是遥控器,将遥控器的每个插槽,对应到一个命令这样就能让遥控器变成“调用者”。当按下按钮,相应命令对象的execute()方法就会被调用,其结果就是,接收者(例如:电灯、天花板电扇、音响)的动作被调用。就类似下面这个图:
实现遥控器:
package com.my.commond;
public class RemoteControl {
//遥控器要处理7个开与关的命令,使用相应数组记录这些命令。
Command[] onCommands;
Command[] offCommands;
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;
}
}
public void setCommand(int slot,Command onCommand,Command offCommand){
//setCommand()方法有3个参数,分别是插槽的位置,开的命令、关的命令。这些命令将
//记录开关数组中对应的插槽位置。
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
public void onButtonWasPushed(int slot){
onCommands[slot].execute();
}
public void offButtonWasPushed(int slot){
offCommands[slot].execute();
}
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();
}
}
实现命令:
电灯开关命令
package com.my.commond;
public class LightOffCommand implements Command {
Light light;
public LightOffCommand(Light light){
this.light = light;
}
public void execute(){
light.off();
}
public void undo(){light.on();}
}
音响开关命令
package com.my.commond;
public class StereoOnWithCDCommand implements Command {
Stereo stereo;
public StereoOnWithCDCommand(Stereo stereo){
this.stereo = stereo;
}
public void execute(){
stereo.on();
stereo.setCD();
stereo.setVolume(11);
}
}
测试遥控器:
package com.my.commond;
public class RemoteLoader {
public static void main(String[] args){
RemoteControl remoteControl = new RemoteControl();
Light livingRoomLight = new Light("Living Room");
Light kitchenLight = new Light("Kitchen");
CeilingFan ceilingFan = new CeilingFan("Living Room");
GarageDoor garageDoor = new GarageDoor("");
Stereo stereo = new Stereo("Living Room");
//创建所有电灯命令对象
LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight);
LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight);
LightOnCommand kitchenLightOn = new LightOnCommand(kitchenLight);
LightOffCommand kitchenLightOff = new LightOffCommand(kitchenLight);
//创建吊扇的开与关
CeilingFanOnCommand ceilingFanOn = new CeilingFanOnCommand(ceilingFan);
CeilingFanOffCommand ceilingFanOff= new CeilingFanOffCommand(ceilingFan);
//创建车库门的上与下命令
GarageDoorUpCommand garageDoorUp = new GarageDoorUpCommand(garageDoor);
GarageDoorDownCommand garageDoorDown = new GarageDoorDownCommand(garageDoor);
//创建音响的开与关命令
StereoOnWithCDCommand stereoOnWithCD = new StereoOnWithCDCommand(stereo);
StereoOffCommand stereoOff = new StereoOffCommand(stereo);
remoteControl.setCommand(0,livingRoomLightOn,livingRoomLightOff);
remoteControl.setCommand(1,kitchenLightOn,kitchenLightOff);
remoteControl.setCommand(2,ceilingFanOn,ceilingFanOff);
remoteControl.setCommand(3,stereoOnWithCD,stereoOff);
System.out.println(remoteControl);
remoteControl.onButtonWasPushed(0);
remoteControl.offButtonWasPushed(0);
remoteControl.onButtonWasPushed(1);
remoteControl.offButtonWasPushed(1);
remoteControl.onButtonWasPushed(2);
remoteControl.offButtonWasPushed(2);
remoteControl.onButtonWasPushed(3);
remoteControl.offButtonWasPushed(3);
}
}
run:
完善代码,以增加撤销功能:
package com.my.commond;
public interface Command {
public void execute();
public void undo();//撤销方法
}
开电灯
package com.my.commond;
public class LightOnCommand implements Command {
Light light;
public LightOnCommand(Light light){
this.light = light;
}
public void execute(){
light.on();
}
public void undo(){light.off();}
}
关电灯
package com.my.commond;
public class LightOffCommand implements Command {
Light light;
public LightOffCommand(Light light){
this.light = light;
}
public void execute(){
light.off();
}
public void undo(){light.on();}
}
package com.my.commond;
public class RemoteControlWithUndo {
//遥控器要处理7个开与关的命令,使用相应数组记录这些命令。
Command[] onCommands;
Command[] offCommands;
Command undoCommand;
public RemoteControlWithUndo(){
//实例化并初始化这两个开与关的数组。
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){
//setCommand()方法有3个参数,分别是插槽的位置,开的命令、关的命令。这些命令将
//记录开关数组中对应的插槽位置。
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
//按下按钮时,将命令记录在undoCommand实例变量中。
public void onButtonWasPushed(int slot){
onCommands[slot].execute();
undoCommand = onCommands[slot];
}
//按下按钮时,将命令记录在undoCommand实例变量中。
public void offButtonWasPushed(int slot){
offCommands[slot].execute();
undoCommand = offCommands[slot];
}
//当按下撤销按钮,调用undoCommand实例变量的undo()方法
public void undoButtonWasPushed(){
undoCommand.undo();
}
}
run:
Living Room light on
Living Room light off
---- Remote Control ----
[slot 0]com.my.commond.LightOnCommand com.my.commond.LightOffCommand
[slot 1]com.my.commond.NoCommand com.my.commond.NoCommand
[slot 2]com.my.commond.NoCommand com.my.commond.NoCommand
[slot 3]com.my.commond.NoCommand com.my.commond.NoCommand
[slot 4]com.my.commond.NoCommand com.my.commond.NoCommand
[slot 5]com.my.commond.NoCommand com.my.commond.NoCommand
[slot 6]com.my.commond.NoCommand com.my.commond.NoCommand
Living Room light on
Living Room light off
Living Room light on
---- Remote Control ----
[slot 0]com.my.commond.LightOnCommand com.my.commond.LightOffCommand
[slot 1]com.my.commond.NoCommand com.my.commond.NoCommand
[slot 2]com.my.commond.NoCommand com.my.commond.NoCommand
[slot 3]com.my.commond.NoCommand com.my.commond.NoCommand
[slot 4]com.my.commond.NoCommand com.my.commond.NoCommand
[slot 5]com.my.commond.NoCommand com.my.commond.NoCommand
[slot 6]com.my.commond.NoCommand com.my.commond.NoCommand
Living Room light off
命令模式的应用场景:当需要将发出请求的对象和执行请求的对象解耦的时候,使用命令模式。
宏命令是命令的一种简单的延伸,允许调用多个命令。宏方法也可以支持撤销,这里我就不介绍宏命令,有兴趣的话大家可以查一下命令模式中的宏命令。
下回我们来一起学习适配器模式。
下回我们来一起学习适配器模式。