UndoRedoStack

κ°œμš”

UndoRedoStack은 μ‹€ν–‰ μ·¨μ†Œμ™€ λ‹€μ‹œ 싀행을 ν•˜κΈ° μœ„ν•΄ κ΅¬ν˜„ν•œ λ””μžμΈ νŒ¨ν„΄μ΄μ—μš”.

λ‹€μ–‘ν•œ μ†Œν”„νŠΈμ›¨μ–΄μ—μ„œ 각자의 λ°©λ²•μœΌλ‘œ κ΅¬ν˜„ λ˜μ–΄ μžˆμ§€λ§Œ, μ €λŠ” 쑰금 κ°„λ‹¨ν•˜κ²Œ ν•„μš”ν•œ κΈ°λŠ₯만 κ΅¬ν˜„ν•˜μ—¬ 각 κΈ°λŠ₯듀을 μ•‘μ…˜(Action)으둜 λ‚˜λˆ„μ–΄ λ³΄μ•˜μ–΄μš”.

그리고 각 Action을 묢은 ActionBlock 클래슀λ₯Ό λ§Œλ“€μ–΄ Sequenceλ₯Ό κ΅¬ν˜„ν•˜λ„λ‘ ν–ˆμ–΄μš”.

이λ₯Ό 톡해 λ³΅μž‘ν•œ Undo λ˜λŠ” Redo μž‘μ—…μ„ ν•œλ²ˆμ— 처리 ν•  수 μžˆμ–΄μš”.

IUndoableAction

public interface IUndoableAction
{
    void Do();
    void Undo();
}

ActionBlock

public class ActionBlock : IUndoableAction
{
    private readonly IUndoableAction[] actionSequence;

    public ActionBlock(params IUndoableAction[] actionSequence)
    {
        this.actionSequence = actionSequence;
    }

    public void Do()
    {
        foreach (var action in actionSequence)
            action.Do();
    }

    public void Undo()
    {
        foreach (var action in actionSequence.Reverse())
            action.Undo();
    }

    public override string ToString()
    {
        return string.Join(",", actionSequence.Select(a => a.ToString()));
    }
}

UndoRedoStack

public class UndoRedoStack
{
    private readonly Stack<IUndoableAction> undoStack = new Stack<IUndoableAction>();
    private readonly Stack<IUndoableAction> redoStack = new Stack<IUndoableAction>();

    /// <summary>
    /// μƒˆλ‘œμš΄ μ•‘μ…˜μ„ μž…λ ₯λ°›μ•˜μ„λ•Œ 각 IUndoableAction을 
    /// Implementν•œ 클래슀의 μ•‘μ…˜μ„ μˆ˜ν–‰ν•˜κ³  기쑴의 Redo μŠ€νƒμ€ μ§€μ›Œμ§„λ‹€.
    /// Undo 및 Redo λ©”μ„œλ“œ μˆ˜ν–‰ μ‹œ Implement 된 클래슀의 λ‚΄μš©μ„ μˆ˜ν–‰ν•œλ‹€.
    /// </summary>
    /// <param name="action"></param>
    public void Do(IUndoableAction action)
    {
        action.Do();
        undoStack.Push(action);

        redoStack.Clear();
    }

    public void Undo()
    {
        RunAction(undoStack, redoStack, f => f.Undo());
    }

    public void Redo()
    {
        RunAction(redoStack, undoStack, f => f.Do());
    }

    private static void RunAction(Stack<IUndoableAction> source, Stack<IUndoableAction> target, Action<IUndoableAction> undoRedo)
    {
        if (source.Count <= 0)
            return;

        var action = source.Pop();

        undoRedo(action);
        target.Push(action);
    }
}

Reference.

Last updated