命令模式入门例子:http://blog.csdn.net/dengjili/article/details/79495454
为什么需要undo
很多时候,我们再操作完,命令之后,我们发现,这个功能不是我们想要的,比如我们在文本编辑中,误删除了文本,我们希望通过回退操作,达到之前的状态。像之前的列子,我们打开了灯,但是之后发现,我们不需要开灯,我们也可以通过undo能撤销刚才的命令
加入undo的设计模式
加入具体例子
改造接口
package headfirst.hd.command;
public interface Command {
void execute();
void undo();
}
空对象
package headfirst.hd.command;
//NoCommand对象,什么都不做,通常用于初始化
public class NoCommand implements Command {
@Override
public void execute() {
}
@Override
public void undo() {
}
}
改造功能点灯开
package headfirst.hd.command;
//通过适配器方式,适配出一个开功能
public class LightOn implements Command {
Light light;
public LightOn(Light light) {
this.light = light;
}
@Override
public void execute() {
light.open();
}
@Override
public void undo() {
light.off();
}
}
改造功能点灯关
package headfirst.hd.command;
//通过适配器方式,适配出一个关功能
public class LightOff implements Command {
Light light;
public LightOff(Light light) {
this.light = light;
}
@Override
public void execute() {
light.off();
}
@Override
public void undo() {
light.open();
}
}
改造控制器
package headfirst.hd.command;
//智能家庭控制器
public class HomeRemoteControl {
//8个按钮
Command[] commands;
Command undoCommand;
public HomeRemoteControl() {
commands = new Command[8];
Command noCommand = new NoCommand();
for (int i = 0; i < commands.length; i++) {
commands[i] = noCommand;
}
undoCommand = noCommand;
}
// 将按钮与功能绑定
public void setCommand(int index, Command command) {
this.commands[index] = command;
}
// 按功能键
public void pressButton(int index) {
this.commands[index].execute();
this.undoCommand = this.commands[index];//操作之后才有撤销功能
}
// 撤销键
public void undoPressButton() {
this.undoCommand.undo();
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("\n-------------远程控制-----------\n");
for (int i = 0; i < commands.length; i++) {
Command command = commands[i];
sb.append("命令["+i+"],").append(command.getClass().getName()).append("\n");
}
sb.append("命令[undo],").append(undoCommand.getClass().getName()).append("\n");
return sb.toString();
}
}
测试类
package headfirst.hd.command;
public class DriveTest {
public static void main(String[] args) {
//智能家庭控制器
HomeRemoteControl control = new HomeRemoteControl();
//电器
Light light = new Light();
//功能适配
LightOn lightOn = new LightOn(light);
LightOff lightOff = new LightOff(light);
//绑定
control.setCommand(0, lightOn);
control.setCommand(1, lightOff);
//操作之后才有撤销功能
control.undoPressButton();
System.out.println(control);
//撤销功能为关(相反操作)
control.pressButton(0);
control.undoPressButton();
System.out.println(control);
}
}
测试结果
-------------远程控制-----------
命令[0],headfirst.hd.command.LightOn
命令[1],headfirst.hd.command.LightOff
命令[2],headfirst.hd.command.NoCommand
命令[3],headfirst.hd.command.NoCommand
命令[4],headfirst.hd.command.NoCommand
命令[5],headfirst.hd.command.NoCommand
命令[6],headfirst.hd.command.NoCommand
命令[7],headfirst.hd.command.NoCommand
命令[undo],headfirst.hd.command.NoCommand
打开点灯
关闭点灯
-------------远程控制-----------
命令[0],headfirst.hd.command.LightOn
命令[1],headfirst.hd.command.LightOff
命令[2],headfirst.hd.command.NoCommand
命令[3],headfirst.hd.command.NoCommand
命令[4],headfirst.hd.command.NoCommand
命令[5],headfirst.hd.command.NoCommand
命令[6],headfirst.hd.command.NoCommand
命令[7],headfirst.hd.command.NoCommand
命令[undo],headfirst.hd.command.LightOn
组合命令撤销
CompositeComand 撤销实现
package headfirst.hd.command;
//组合命令
public class CompositeComand implements Command {
Command[] commands;
public CompositeComand(Command[] commands) {
this.commands = commands;
}
@Override
public void execute() {
for (Command command : commands) {
command.execute();
}
}
@Override
public void undo() {
for (Command command : commands) {
command.undo();
}
}
}
多次undo实现
类似于phototshop这类软件,我们可以撤销很多次,但是是有次数限制。文本编辑也是,我们可以回退很多次操作。
智能家庭控制器代码的修改
package headfirst.hd.command;
//智能家庭控制器
public class HomeRemoteControl {
final Command noCommand = new NoCommand();
//8个按钮
Command[] commands;
//循环队列使用,最多保持3个命令,及最多回退三个命令
final int SIZE = 3;
int INDEX = 0;
Command[] undoCommands = new Command[SIZE];
public HomeRemoteControl() {
commands = new Command[8];
for (int i = 0; i < commands.length; i++) {
commands[i] = noCommand;
}
for (int i = 0; i < undoCommands.length; i++) {
undoCommands[i] = noCommand;
}
}
// 将按钮与功能绑定
public void setCommand(int index, Command command) {
this.commands[index] = command;
}
// 按功能键
public void pressButton(int index) {
this.commands[index].execute();
this.undoCommands[INDEX] = this.commands[index];//操作之后才有撤销功能
INDEX = (INDEX + 1) % SIZE; //循环队列基本逻辑,但是不是先进先出
}
// 撤销键
public void undoPressButton() {
INDEX = (INDEX - 1 + SIZE) % SIZE; //循环队列基本逻辑,但是不是先进先出
//逻辑可取非,去掉这个分支,这里似乎为了能够看到效果
if (undoCommands[INDEX].getClass().equals(NoCommand.class)) {
System.out.println("当前没有命令了");
} else {
undoCommands[INDEX].undo();
undoCommands[INDEX] = noCommand;
}
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("\n-------------远程控制-----------\n");
for (int i = 0; i < commands.length; i++) {
Command command = commands[i];
sb.append("命令["+i+"],").append(command.getClass().getName()).append("\n");
}
//sb.append("命令[undo],").append(undoCommand.getClass().getName()).append("\n");
return sb.toString();
}
}
测试
package headfirst.hd.command;
public class DriveTest {
public static void main(String[] args) {
//智能家庭控制器
HomeRemoteControl control = new HomeRemoteControl();
//电器
Light light = new Light();
//功能适配
LightOn lightOn = new LightOn(light);
LightOff lightOff = new LightOff(light);
//绑定
control.setCommand(0, lightOn);
control.setCommand(1, lightOff);
//操作之后才有撤销功能
control.undoPressButton();
//撤销功能为关(相反操作)
control.pressButton(0);
control.undoPressButton();
//当前只保持了一个命令
control.undoPressButton();
control.pressButton(0);
control.pressButton(0);
control.pressButton(0);
control.pressButton(0);
control.undoPressButton();
control.undoPressButton();
control.undoPressButton();
//最多保持三个命令
control.undoPressButton();
}
}
测试结果
当前没有命令了
打开点灯
关闭点灯
当前没有命令了
打开点灯
打开点灯
打开点灯
打开点灯
关闭点灯
关闭点灯
关闭点灯
当前没有命令了
同上,加入redo
很多时候,我们操作完命令之后,我们发现,这个功能我们还是想要的,比如我们在文本编辑中,我们需要将一份文件复制到多个地方,命令需要执行多次。像之前的列子,我们增加电视的音量,我们需要多次使命同一个命令
加入undo的设计模式
改变接口
package headfirst.hd.command;
//NoCommand对象,什么都不做,通常用于初始化
public class NoCommand implements Command {
@Override
public void execute() {
}
@Override
public void undo() {
}
@Override
public void redo() {
}
}
控制器的改造HomeRemoteControl
//智能家庭控制器
public class HomeRemoteControl {
//添加redo命令
Command redoCommand;
//添加复制,按钮功能等,同上,比较简单
这里不再测试
undo应用
数据库回退:http://blog.csdn.net/dengjili/article/details/79547370