How to Implement Undo/Redo in Java

Undoing and redoing can be implemented in your programs by using the Command pattern. The Command pattern is a design pattern where objects represent commands. That is, objects contain some statements to be executed. These statements operate on some data to change its state.

To add undo functionality, add another set of statements changing the state of the data to the way it was before. This is easy to do and can be done in a few steps.

 

1.     Make an interface with two methods, undo() and redo().

Example:

interface UndoableCommand
 {
        void undo();
        void redo();
 }

 

2.     Create a class implementing it, which does your desired command. For example, UndoableListAdd, which undoes adding to a List. Any command you wish is acceptable, except that the data that is operated on must be mutable (that is, objects and not primitives).

Example: a class that will erase an element from an array, with what variables it should hold.

class UndoableErase implements UndoableCommand
 {
        //variables saving array, index to erase, and element.
        Object[] array;
        int index;
        Object oldval;
 }

 

3. In constructor, assign the data to instance variable(s).

Example: the constructor for my class would save array and its state details of old element and index to erase and apply erase operation (unset array slot at index). It takes an array and an index as arguments to the constructor.

        UndoableErase(Object[] array, int index)
        {
               //save the array and index to erase.
               this.index = index;
               this.array = array;
               this.oldval = array[index];
 
               //erase.
               array[index] = null;
        }

 

4. In undo(), set saved data to its old state (before the command).

READ  Design Patterns

Example: the undo() command for my class sets the array to old state (set element at index to old element).

        public void undo()
        {
               array[index] = oldval;
        }

 

5. In redo(), set saved data to its new state (after the command).

Example: the redo() for my class would set the array to new state (unset array slot at index).

        public void redo()
        {
               array[index] = null;
        } 

(Note: executing the command is the same as calling redo())

My example put together looks like this:

class UndoableErase implements UndoableCommand
 {
        //fields saving array, index to erase, and element.
        Object[] array;
        int index;
        Object oldval;
 
        UndoableErase(Object[] array, int index)
        {
               //save the array and index to erase.
               this.index = index;
               this.array = array;
               this.oldval = array[index];
 
               //erase.
               array[index] = null;
        }
 
        public void undo()
        {
               array[index] = oldval;
        }
 
        public void redo()
        {
               array[index] = null;
        }
 }

The tester for my example looks like this:

class Tester
{
    public static void main(String[] args)
    {
         //make array.
         Object[] array = new Object[] {1, 2, 3};
 
         //apply operation on it.
         UndoableOp op = new UndoableErase(array, 1);
         System.out.println(Arrays.toString(array)); //[1, null, 3]
 
         //undo that.
         op.undo();
         System.out.println(Arrays.toString(array)); //[1, 2, 3]
 
         //redo that.
         op.redo();
         System.out.println(Arrays.toString(array)); //[1, null, 3]
     }
}
Please like & share: