【问题标题】:Undo/redo memento pattern c#撤消/重做备忘录模式c#
【发布时间】:2017-06-28 20:52:32
【问题描述】:

我正在尝试在 C#(treeView 组件)中为树的节点实现撤消/重做功能。我使用了纪念品模式,但我在重做部分遇到了麻烦。我看不出我的逻辑在哪里有缺陷。以下是一些代码截图

    private List<Memento> _mementoStateList= new List<Memento>();
    private List<Memento> _undoStateList= new List<Memento>();
    public Memento Memento { get{return null;}
        set{_mementoStateList.Add(value);} }

    public Memento Undo()
    {
        if (!_mementoStateList.Any()) return null;
        Memento m = _mementoStateList.Last();
        _undoStateList.Add(m);
        _mementoStateList.Remove(m);
        return m;
    }

    public Memento Redo()
    {
        if (!_undoStateList.Any()) return null;
        Memento m = _undoStateList.Last();
        _mementoStateList.Add(m);
        _undoStateList.Remove(m);
        return m;
    }

在我的表单中,在删除节点之前,我调用了 SaveMemento() 方法,该方法创建了一个表示当前状态的新 Memento 对象。对象被添加到 _mementoStateList。

当撤消和重做一个动作时,我调用上面的 Undo() 和 Redo() 方法。

我假设我没有在正确的时刻保存状态? 任何意见都非常感谢!

【问题讨论】:

  • 当你设置一个新的纪念品时,你应该重置你的 undo-state-list... 否则这个列表可能会得到一个非常奇怪的内容是某些用例。

标签: c# design-patterns undo redo memento


【解决方案1】:

也许您应该考虑使用Command 模式实现撤消/重做,而使用Memento 如果您需要存储大量状态(实际上问题是您将支持多少撤消操作),那么实现可以是重。

【讨论】:

    【解决方案2】:

    当您创建备忘录时,您必须对对象树进行深度克隆,否则备忘录将只是对当前状态的引用。在这种情况下,对状态的任何更改都会反映到所有纪念品上,从而破坏任何保留先前(或潜在未来)状态历史的尝试。

    【讨论】:

    • 我确实在克隆根元素并将其存储为 TreeNode。
    • 我认为深度克隆是一种痛苦。命令模式是纪念品模式的完美搭档。
    • 这可能还不够,因为从根节点到更深节点的引用仍然指向当前状态。如果你只是克隆根,那最多是一个浅克隆。对于深度克隆,您必须访问树并克隆该过程中的所有对象(包括装箱的整数,如果有的话)。唯一的例外是字符串,它本质上是在更改时创建的。
    • @jlvaquero 我同意,存储状态也意味着分配大量内存。在某些情况下这可能不可行,而命令模式效率更高,但需要更深入地了解您正在做什么。一个缺点是,对于没有和反向操作的操作,在 UNDO 上,您必须重做所有先前的命令,直到完全保存状态才能重新建立正确的状态。因此,如果每个动作都有逆动作,那么 memento 中的命令是完美的,否则它也会变得复杂。
    猜你喜欢
    • 2011-03-16
    • 2013-12-20
    • 1970-01-01
    • 1970-01-01
    • 2021-01-22
    • 1970-01-01
    • 2012-04-08
    • 2012-07-09
    • 1970-01-01
    相关资源
    最近更新 更多