TL;DR: 通过实现 Command(第233页)和 Memento(第283页)模式,您可以支持撤消和重做操作。(设计模式 - Gamma等人)。
Memento模式
这个简单模式允许您保存对象的状态。只需在新类中包装对象,并在其状态更改时进行更新。
public class Memento
{
MyObject myObject;
public MyObject getState()
{
return myObject;
}
public void setState(MyObject myObject)
{
this.myObject = myObject;
}
}
命令模式
命令模式存储原始对象(我们想要支持撤销/重做的对象)和备忘录对象,在撤销时需要使用备忘录对象。此外,定义了两种方法:
- execute:执行命令
- unExecute:撤销命令
代码:
public abstract class Command
{
MyObject myObject;
Memento memento;
public abstract void execute();
public abstract void unExecute();
}
他们定义了逻辑“操作”,扩展命令(例如插入):
public class InsertCharacterCommand extends Command
{
public InsertCharacterCommand()
{
}
@Override public void execute()
{
}
@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
等。此外,相同的模式适用于任何类型的对象,使得该设计在不同的使用场景下具有可重用性和可修改性。