TL;DR:您可以通过实现命令 (p.233) 和 Memento (p.283) 模式(设计模式 - Gamma 等)来支持撤消和重做操作。
纪念品图案
此简单模式允许您保存对象的状态。只需将对象包装在新类中,每当其状态更改时,请更新它。
public class Memento
{
MyObject myObject;
public MyObject getState()
{
return myObject;
}
public void setState(MyObject myObject)
{
this.myObject = myObject;
}
}
命令模式
Command 模式存储原始对象(我们希望支持撤消/重做)和 memento 对象,在撤消时需要它们。此外,还定义了 2 种方法:
-
执行:执行命令
-
取消执行:删除命令
法典:
public abstract class Command
{
MyObject myObject;
Memento memento;
public abstract void execute();
public abstract void unExecute();
}
它们定义了扩展命令的逻辑“操作”(例如插入):
public class InsertCharacterCommand extends Command
{
//members..
public InsertCharacterCommand()
{
//instantiate
}
@Override public void execute()
{
//create Memento before executing
//set new state
}
@Override public void unExecute()
{
this.myObject = memento.getState()l
}
}
应用模式:
最后一步定义撤消/重做行为。核心思想是存储一堆命令,该命令用作命令的历史记录列表。若要支持重做,可以在应用撤消命令时保留辅助指针。请注意,每当插入新对象时,都会删除其当前位置之后的所有命令;这是通过下面定义的方法实现的:deleteElementsAfterPointer
private int undoRedoPointer = -1;
private Stack<Command> commandStack = new Stack<>();
private void insertCommand()
{
deleteElementsAfterPointer(undoRedoPointer);
Command command =
new InsertCharacterCommand();
command.execute();
commandStack.push(command);
undoRedoPointer++;
}
private void deleteElementsAfterPointer(int undoRedoPointer)
{
if(commandStack.size()<1)return;
for(int i = commandStack.size()-1; i > undoRedoPointer; i--)
{
commandStack.remove(i);
}
}
private void undo()
{
Command command = commandStack.get(undoRedoPointer);
command.unExecute();
undoRedoPointer--;
}
private void redo()
{
if(undoRedoPointer == commandStack.size() - 1)
return;
undoRedoPointer++;
Command command = commandStack.get(undoRedoPointer);
command.execute();
}
结论:
这种设计之所以强大,是因为您可以根据需要添加任意数量的命令(通过扩展类),例如 ,等等。此外,相同的模式适用于任何类型的对象,使设计在不同的用例中可重用和修改。Command
RemoveCommand
UpdateCommand