Using memo mode to realize Undo and Redo

Keywords: Java

The memo model has three roles.
1. Originator role: responsible for creating a memo to record the internal status of the current time, and can use the memo to restore the internal status. Implement other business functions.
2. Memo role: responsible for storing the internal status of the initiator.
3. Caretaker role: manage memos, provide the function of saving and obtaining memos, but it cannot access and modify the contents of memos.

/**
 * Initiator role
 *
 */
public class UnRedoOriginator {
    private String state;

    public UnRedoOriginator() {
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }

    public Memento createMemento() {
        return new Memento(state);
    }

    public void restoreMemento(Memento m) {
        if (m != null) {
            this.setState(m.getState());
        } else {
            System.out.println("No state to recover");
        }
    }
}
/**
 * Memorandum
 *
 */
public class Memento {
    private String state;

    public Memento(String state) {
        this.state = state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }
}
/**
 * Memo managers of undo and redo
 *
 */
public class UnRedoCaretaker {
    /* Memo list */
    private List<Memento> mementoList;
    /* Memo list capacity, memo list capacity = maximum number of backward + 1 */
    private int capacity = 3;
    /* Backward index */
    private int undoIndex = -2;
    /* Forward index */
    private int redoIndex = 0;

    public UnRedoCaretaker() {
        this.mementoList = new LinkedList<>();
    }

    public UnRedoCaretaker(int capacity) {
        this();
        this.capacity = capacity;
    }

    /**
     * Add memo
     * 
     * @param memento
     */
    public void addMemento(Memento memento) {
        // Before adding a note, remove the note after the current status
        for (int i = this.mementoList.size() - 1; i > this.undoIndex + 1; i--) {
            this.mementoList.remove(i);
        }

        if (this.mementoList.size() >= this.capacity) {
            this.mementoList.remove(0);
        }
        this.mementoList.add(memento);

        this.undoIndex = this.mementoList.size() - 2;
        this.redoIndex = this.mementoList.size();
    }

    /**
     * Backward operation
     * 
     * @return
     */
    public Memento undo() {
        Memento result = null;

        if (this.undoIndex >= 0 && this.undoIndex < this.mementoList.size() - 1) {
            result = this.mementoList.get(this.undoIndex);

            this.undoIndex--;
            this.redoIndex--;
        }

        return result;
    }

    /**
     * Forward operation
     * 
     * @return
     */
    public Memento redo() {
        Memento result = null;
        if (this.redoIndex > 0 && this.redoIndex < this.mementoList.size()) {
            result = this.mementoList.get(this.redoIndex);

            this.redoIndex++;
            this.undoIndex++;
        }

        return result;
    }
}

Aggregate the initiator role and memo manager role, and modify the initiator role class.

/**
 * Initiator role
 *
 */
public class UnRedoOriginator {
    private String state;
    private UnRedoCaretaker caretaker;

    public UnRedoOriginator() {
        this.caretaker = new UnRedoCaretaker(3);
    }

    private void setState(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }

    private Memento createMemento() {
        return new Memento(state);
    }

    private void restoreMemento(Memento m) {
        if (m != null) {
            this.setState(m.getState());
        } else {
            System.out.println("No state to recover");
        }
    }

    public void setAndStoreState(String state) {
        this.setState(state);
        caretaker.addMemento(this.createMemento());
    }

    public void undo() {
        this.restoreMemento(caretaker.undo());
    }

    public void redo() {
        this.restoreMemento(caretaker.redo());
    }
}

Test.

/**
 * Test undo and redo
 * 
 */
public class TestUnRedo {

    public static void main(String[] args) {
        UnRedoOriginator or = new UnRedoOriginator();

        /* Status forward / backward not set */
        or.undo();
        or.redo();

        /* Continuous add operation */
        System.out.println();
        int num = 1;
        operation(or, num++);
        operation(or, num++);
        operation(or, num++);
        operation(or, num++);

        /* The number of backward times exceeds the number of backward times */
        back(or);
        back(or);
        back(or);

        /* Add a new action when backing up, and then back up */
        System.out.println();
        operation(or, num++);
        back(or);
        forward(or);
        forward(or);// Advance times more than can be advanced times

        /* Add a new action when backing up, and redo */
        System.out.println();
        back(or);
        operation(or, num++);
        forward(or);
    }

    private static void operation(UnRedoOriginator or, int name) {
        System.out.println("*******operation*******");
        or.setAndStoreState("operation" + name);
        System.out.println("Current status:" + or.getState());
    }

    private static void back(UnRedoOriginator or) {
        System.out.println("-------Back off-------");
        or.undo();
        System.out.println("Current status:" + or.getState());
    }

    private static void forward(UnRedoOriginator or) {
        System.out.println("=======Forward=======");
        or.redo();
        System.out.println("Current status:" + or.getState());
    }

}

The results are as follows.

No state to recover
 No state to recover

*******Operation*******
Current status: operation 1
 *******Operation*******
Current status: operation 2
 *******Operation*******
Current status: operation 3
 *******Operation*******
Current status: operation 4
 -------Back up-------
Current status: operation 3
 -------Back up-------
Current status: operation 2
 -------Back up-------
No state to recover
 Current status: operation 2

*******Operation*******
Current status: operation 5
 -------Back up-------
Current status: operation 2
 =======Forward=======
Current status: operation 5
 =======Forward=======
No state to recover
 Current status: operation 5

-------Back up-------
Current status: operation 2
 *******Operation*******
Current status: operation 6
 =======Forward=======
No state to recover
 Current status: operation 6

Posted by auteejay on Tue, 22 Oct 2019 03:44:59 -0700