How does Undo work?

2019-03-29 23:12发布

问题:

How does undo work? Does it copy all the managed objects every time any of the values change? Or does it only copy the actual changes together with an information which objects were affected? Is that heavy or lightweight?

回答1:

The 'undo' mechanism for pretty much any language that supports Object-Oriented constructs uses the Memento Design Pattern to make it happen.



回答2:

Here's a rough implementation to get you thinking. This handles your stack of undoable operations. (It doesn't handle redo, but that's easy to support by replacing the stack with a list and keeping track of the current item.)

public class Undoable {
    public static void Do(Action do, Action undo) {
        do();
        sUndoStack.Push(new Undoable(do, undo));
    }

    public static void Undo() {
        sUndoStack.Pop().mUndoCallback();
    }

    private Undoable(Action doCallback, undoCallback) {
        mDoCallback = doCallback;
        mUndoCallback = undoCallback;
    }

    private Action mDoCallback, mUndoCallback;

    // note: using a global stack here is lame, but works for demo purposes
    private static readonly Stack<Undoable> sUndoStack = new Stack<Undoable>();
}

To use this, let's say the user can change a value in some object like this:

public class Foo {
    public string Bar {
        get { return mBar; }
        set {
            if (mBar != value) {
                mBar = value;
            }
        }
    }

    private string mBar;
}

To make that operation undoable, we just change the setter to:

set {
    if (mBar != value) {
        string oldValue = mBar;
        Undoable.Do(() => mBar = value,
                    () => mBar = oldValue);
    }
}

Now, if you call Undoable.Undo() from anywhere in the application, your instance of Foo will restore the previous value of Bar. If Foo also raises an event when Bar changes (not shown here), the UI will also properly refresh on undo too.