c++ - MVC 设计中的撤消功能

标签 c++ design-patterns

我有一个根据经典 Model-View-Controller pattern 设计的 C++ 应用程序.该模型由外部源通过 Controller 接口(interface)通过 Command pattern 进行修改。 .命令由 Action 对象(及其派生对象)表示。

现在我希望能够撤消修改,但我的问题是我的 Controller 中没有 getter,只有 setter。这看起来很合乎逻辑,因为没有理由有人应该能够通过 Controller 获取有关模型的信息。因此,我不能让我的 Action 对象存储模型的状态,因为它们无权访问它。

如何解决这个问题?我想让我的应用程序尽可能地可扩展,但我不太确定哪个选项最适合。到目前为止我想到的方法是:

  1. 将 getter 方法放入 Controller 中。这似乎违背了 MVC 模式。
  2. 为 Action 提供指向 View 的指针。该行动然后可以:
    1. 使用单独的 getter 来获取要修改的模型的特定元素的状态。
    2. 使用 Memento Viewer 实现的方法。

也许有更好的方法来做到这一点?现在,最好的选择似乎是 2,子选项 1(对于子选项 2,我很可能存储比撤消一个操作所需的更多的状态)。

注意:我知道还有其他关于如何实现撤消操作的问题。然而,我找到的唯一答案给出了使用 Command 或 Memento 模式的建议。我知道这很可能是要走的路。我要问的是如何在 MVC 设计中尽可能干净且可扩展地集成它。

[编辑] 我不喜欢 Memento 模式的一点是它迫使我存储一个完整的状态。假设我的模型是一个 1000x1000 矩阵,我的命令是 ChangeOneValueAtLocation。为了能够撤消其更改,ChangeOneValueAtLocation 对象只需要存储它正在更改的位置的先前值,但 Memento 似乎不可能做到这一点。我的模型越大,这个问题就越严重。

[编辑 2] 在这个应用程序的特定情况下,我对 Memento 的另一个问题是:对于 Command 对象可以在模型上执行的每个方法,都有一个方法完全相反(或者可以很容易被哄骗这样做)。这就是为什么我会觉得必须存储整个状态是一种浪费,应该没有必要,恢复单个命令非常简单,唯一的问题是获取数据才能做到这一点。

此外,我不需要能够撤消特定命令,只需撤消历史堆栈中最顶层的命令即可。

最佳答案

我还支持包含撤消支持的模型层。在模型端有很多方法可以处理这个问题。第一个也是最明显的是模型本身通过“标签”记住更改的历史,但这可能很难同步所有模型类。

另一种选择是创建一个具有“事务”概念的历史管理器,这会导致它生成一个撤消点,并为您的模型拍摄快照,或开始记录更改(以减少内存使用),或记录导致模型更改的命令等。模型将更改通知经理,最后您完成事务(或不完成,因为下一个事务的开始可能是前一个事务的结束)。一旦添加了回滚到某个点的能力,工作就完成了。通过使这个管理器类中的事情稍微复杂一些,您可以创建一个撤消树(就像 emacs 中的那样),因此它也是一种非常灵活的方法来处理它。

不过,上面的解决方案并不完全在模型层。它是一个由模型和 Controller 共同驱动的支持类。如果去掉事务概念,那么它完全是模型驱动的,但是实现撤销操作的概念可能有些棘手。如果您将其更改为充当命令代理,则它是您的 Controller 使用的唯一实体,并且显然是一个模型。在这一点上选择一种方法而不是另一种方法的设计太粗糙了,但我倾向于“事务”模型。感觉很容易实现。

关于c++ - MVC 设计中的撤消功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5695430/

相关文章:

c# - 这是构建灵活实现的合理方法吗

c++ - 使用数据文件排序计算时遇到问题

c++ - 如何按顺序迭代几个容器?

c++ - 如何编写模板函数,其参数类型需要继承某个类

c++ - 观察者常量正确性

c++ - 处理抽象工厂中的具体类爆炸

java - 回调重复代码

c++ - c++如何将6e(或带e的任何数字)解释为输入?

c++ - C++中的模块化编程

c# - 在选择设计模式方面需要帮助