TL; DR: Puede admitir acciones de deshacer y rehacer implementando los patrones Command y Memento (Design Patterns - Gama et. al).
El patrón Memento
Este patrón simple le permite guardar los estados de un objeto. Simplemente envuelva el objeto en una nueva clase y cada vez que cambie su estado, actualícelo.
public class Memento
{
MyObject myObject;
public MyObject getState()
{
return myObject;
}
public void setState(MyObject myObject)
{
this.myObject = myObject;
}
}
El patrón Comando
El patrón de comando almacena el objeto original (que queremos apoyar deshacer/rehacer) y el objeto de recuerdo, lo que necesitamos en caso de deshacer.Por otra parte, se definen 2 métodos:
- ejecutar: ejecuta el comando
- unExecute: elimina el comando
Código:
public abstract class Command
{
MyObject myObject;
Memento memento;
public abstract void execute();
public abstract void unExecute();
}
La definir la lógica " Acciones "que extienden el Comando (por ejemplo, Insertar):
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
}
}
Aplicando los patrones:
Este último paso define el comportamiento de deshacer/rehacer. La idea central es almacenar una pila de comandos que funcione como una lista histórica de los comandos. Para admitir rehacer, puede mantener un puntero secundario siempre que se aplique un comando de deshacer. Tenga en cuenta que cada vez que se inserta un objeto nuevo, se eliminan todos los comandos después de su posición actual; eso se logra mediante el método deleteElementsAfterPointer
se definen a continuación:
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();
}
Conclusión:
Lo que hace este diseño de gran alcance es el hecho de que se pueden añadir tantos comandos como desee (extendiendo la clase Command
) por ejemplo, , RemoveCommand
, UpdateCommand
y así sucesivamente. Además, el mismo patrón es aplicable a cualquier tipo de objeto, haciendo que el diseño reutilizable y se pueda modificar en diferentes casos de uso.
Asegúrese de echar un vistazo al soporte de deshacer integrado; Nunca lo he usado y no puedo encontrar un tutorial de Swing para él, pero [aquí] (http://docs.oracle.com/javase/6/docs/api/javax/swing/undo/UndoManager.html) es el gerente. –