本文已参与「新人创作礼」活动,一起开启掘金创作之路
首先来看看命令模式的概念
将请求封装成对象,以便使用不同的请求、队列或日志来参数化其他对象,同时命令模式也支持撤销的操作
现在假设我们需要一个只能遥控器,可以控制家里各种家具,遥控器有多个按钮,分别对应电灯、电视、空调等家具
我们先来实现开关电灯的功能
电灯实体类必不可少
public class Light {
public void on(){
System.out.println("打开电灯");
}
public void off() {
System.out.println("关闭电灯");
}
}
创建一个可以让所有命令对象实现的一个方法接口
public interface Command {
public void execute();
}
打开电灯命令类实现这个命令接口
public class LightOnCommand implements Command{
Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.on();
}
}
接下里我们创建一个遥控器
public class SimpleRemoteControl {
//遥控器的按钮
Command slot;
public SimpleRemoteControl() {}
public void setCommand(Command command) {
slot = command;
}
public void buttonWasPressed() {
slot.execute();
}
}
到此为止,我们已经把打开电灯的按钮放进遥控器了
public class RemoteControlTest {
public static void main(String[] args) {
SimpleRemoteControl simpleRemoteControl = new SimpleRemoteControl();
Light light = new Light();
LightOnCommand lightOnCommand = new LightOnCommand(light);
simpleRemoteControl.setCommand(lightOnCommand);
simpleRemoteControl.buttonWasPressed();
}
}
运行后即可打印出:打开电灯
遥控器怎么可能只有一个按钮呢?现在我们要把更多家具更多的命令加进来
先改造一下遥控器
public class RemoteControl {
//打开命令
Command[] onCommands;
//关闭命令
Command[] offCommands;
public RemoteControl() {
// 需要控制几个家具就设置多长的数组
onCommands = new Command[3];
offCommands = new Command[3];
//初始命令默认为无命令(NoCommand类在下方附上)
Command noCommand = new NoCommand();
for(int i = 0; i < 3; i++) {
onCommands[i] = noCommand;
offCommands[i] = noCommand;
}
}
//给按钮安置命令
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();
}
}
NoCommand类
public class NoCommand implements Command{
@Override
public void execute() {
System.out.println("暂未加入命令");
}
}
自己再像之前的LightOnCommand一样多添加几个家具对应的命令,进行测试,我这里就只加了一个
public class RemoteLoader {
public static void main(String[] args) {
RemoteControl remoteControl = new RemoteControl();
Light light = new Light();
//……此处可以添加其他家具
LightOnCommand lightOnCommand = new LightOnCommand(light);
LightOffCommand lightOffCommand = new LightOffCommand(light);
//……此处可以添加其他命令
remoteControl.setCommand(0, lightOnCommand, lightOffCommand);
remoteControl.onButtonWasPushed(0);
remoteControl.offButtonWasPushed(0);
}
}
运行代码,输出:打开电灯,关闭电灯
最后一步,实现撤销的功能
首先在Command接口中添加一个undo()抽象方法
public interface Command {
public void execute();
public void undo(); //新添加
}
再对打开电灯命令进行一点改造
public class LightOnCommand implements Command{
Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.on();
}
//打开电灯的撤销功能就是关闭电灯
@Override
public void undo() {
light.off();
}
}
我们还需要知道最后一个按下的按钮是哪一个,这样才能准确实现撤销功能
对遥控器添加一点代码
public class RemoteControl {
Command[] onCommands;
Command[] offCommands;
Command undoCommand; //记录最后按下的按钮
public RemoteControl() {
onCommands = new Command[3];
offCommands = new Command[3];
Command noCommand = new NoCommand();
for(int i = 0; i < 3; 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 = offCommands[slot];
}
public void undoButtonWasPushed() {
undoCommand.undo();
}
}
最终测试
public class RemoteLoader {
public static void main(String[] args) {
RemoteControl remoteControl = new RemoteControl();
Light light = new Light();
LightOnCommand lightOnCommand = new LightOnCommand(light);
LightOffCommand lightOffCommand = new LightOffCommand(light);
remoteControl.setCommand(0, lightOnCommand, lightOffCommand);
remoteControl.onButtonWasPushed(0);
remoteControl.offButtonWasPushed(0);
remoteControl.undoButtonWasPushed();
}
}
运行结果:打开电灯,关闭电灯,打开电灯
正确执行了撤销效果