命令模式
一、定义
将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销操作。
二、结构
客户、命令、接受命令执行者、被命令对象
- 命令:Command接口及具体命令对象(open、close、undo),调用被命令对象的具体方法。
- 被命令对象:Light灯具等设备,包含open、close等具体操作方法。
- Invoker(接受命令执行者):设置命令,并且执行者,包含setCommand、execute和undo方法。
实例:灯具、门设备开关
Device设备
//灯具
public class Light {
public void on() {
System.out.println("Light on");
}
public void off() {
System.out.println("Light off");
}
}
//车库门
public class GarageDoor {
public void open() {
System.out.println("GarageDoor open");
}
public void close() {
System.out.println("GarageDoor close");
}
}
Command命令
public interface Command {
public void execute();
public void undo();
}
//灯具开启命令(关闭类似)
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 GarageDoorOpenCommand implements Command{
GarageDoor door;
public GarageDoorOpenCommand(GarageDoor door) {
this.door = door;
}
public void execute() {
door.open();
}
public void undo() {
door.close();
}
}
//空命令
public class UnCommand implements Command{
public void execute() {
}
public void undo() {
}
}
Invoker调用者
//简单遥控器
public class SimpleRemoteControl {
Command slot;
Command undoCommand;
public void setCommand(Command command) {
slot = command;
}
public void buttonWasPressed() {
slot.execute();
undoCommand = slot;
}
public void undoButtonWasPressed() {
undoCommand.undo();
}
}
Client客户
public class SimpleClient {
public static void main(String[] args) {
// 灯具开启
SimpleRemoteControl simpleRemoteControl = new SimpleRemoteControl();
simpleRemoteControl.setCommand(new LightOnCommand(new Light()));
simpleRemoteControl.buttonWasPressed();
// 车库门开启
simpleRemoteControl.setCommand(new GarageDoorOpenCommand(new GarageDoor()));
simpleRemoteControl.buttonWasPressed();
//撤销上一个命令
simpleRemoteControl.undoButtonWasPressed();
}
}
三、撤销和宏命令
撤销操作可以使用栈记录执行过的命令,在undo时以此取出栈顶命令,并且执行其undo方法。
宏命令就是用数组记录所有命令,并且遍历执行。
四、命令的更多用途
1、队列请求
将命令接口的对象,放入队列中,在线程可用时,从队列取出命令并且执行execute。在这种情况下,命令模式是非常好用的。
2、日志请求
电子表格等文件,需要将操作存储在硬盘中,当出现死机之后,从硬盘中获取之前的操作并且恢复。而不是采用每次操作都将整个电子表格等数据都存储一边。
模式的形式:
1、每次执行操作,都通过invoker(接受命令并且执行者)调用execute
将数据存储(store)到硬盘中
2、出现死机,开始进行恢复
3、通过invoker调用execute
将数据从硬盘中加载出来(load)
这样就满足了日志的需求。