TL; DR: Sie können Aktionen zum Rückgängigmachen und Wiederherstellen unterstützen, indem Sie die Befehls- und Memento-Muster implementieren (Design Patterns - Gama et. al).
Das Memento Pattern
Dieses einfache Muster können Sie die Zustände eines Objekts speichern. Wickeln Sie das Objekt einfach in eine neue Klasse und aktualisieren Sie es, sobald sich sein Status ändert.
public class Memento
{
MyObject myObject;
public MyObject getState()
{
return myObject;
}
public void setState(MyObject myObject)
{
this.myObject = myObject;
}
}
Das Command-Muster
Das Befehlsmuster speichert das ursprüngliche Objekt und das memento Objekt (das wir Undo/Redo unterstützen möchten), die wir im Fall eines Undo benötigen.Darüber hinaus sind 2-Methoden definiert:
- auszuführen: führt den Befehl
- unExecute: entfernt den Befehl
Code:
public abstract class Command
{
MyObject myObject;
Memento memento;
public abstract void execute();
public abstract void unExecute();
}
Die definieren die logische " Aktionen, die den Befehl erweitern (zB Einfügen):
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
}
}
Auftragen der Muster:
Dieser letzte Schritt definiert die Undo/Redo-Verhalten. Ihre Kernidee besteht darin, einen Stapel von Befehlen zu speichern, der als Verlaufsliste der Befehle fungiert. Um Redo zu unterstützen, können Sie einen sekundären Zeiger beibehalten, wenn ein Rückgängig-Befehl angewendet wird. Beachten Sie, dass jedes Mal, wenn ein neues Objekt eingefügt wird, alle Befehle nach ihrer aktuellen Position entfernt werden; dass durch die deleteElementsAfterPointer
Methode erreicht hat folgende Bedeutung haben:
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();
}
Fazit:
Was dieser Entwurf mächtig macht, ist die Tatsache, dass Sie so viele Befehle hinzufügen können, wie Sie möchten (durch die Command
Klasse erweitern), zB , RemoveCommand
, UpdateCommand
und so weiter. Darüber hinaus gilt das gleiche Muster für jede Art von Objekt, so dass das Design wiederverwendbar und veränderbar über verschiedene Anwendungsfälle.
Werfen Sie einen Blick auf die integrierte Rückgängig-Unterstützung; Ich habe es nie benutzt und ich kann kein Swing-Tutorial dafür finden, aber [hier] (http://docs.oracle.com/javase/6/docs/api/javax/swing/undo/UndoManager.html) ist der Manager. –