TL;DR:您可以通过实现命令和备忘录模式(设计模式 - Gama 等)来支持撤消和重做操作。
备忘录模式
这个简单的模式允许您保存对象的状态。只需将对象包装在一个新类中,只要它的状态发生变化,就更新它。
public class Memento
{
MyObject myObject;
public MyObject getState()
{
return myObject;
}
public void setState(MyObject myObject)
{
this.myObject = myObject;
}
}
命令模式
命令模式存储原始对象(我们希望支持撤消/重做)和备忘录对象,我们在撤消时需要这些对象。此外,还定义了 2 种方法:
- 执行:执行命令
- unExecute:删除命令
代码:
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
。此外,相同的模式适用于任何类型的对象,使设计可在不同的用例中重用和修改。