Java设计模式学习笔记——命令模式

246 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

首先来看看命令模式的概念

将请求封装成对象,以便使用不同的请求、队列或日志来参数化其他对象,同时命令模式也支持撤销的操作

现在假设我们需要一个只能遥控器,可以控制家里各种家具,遥控器有多个按钮,分别对应电灯、电视、空调等家具

我们先来实现开关电灯的功能

电灯实体类必不可少

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();
	}

}

运行结果:打开电灯,关闭电灯,打开电灯

正确执行了撤销效果