首页 > 解决方案 > 撤消重做一个巨大的对象

问题描述

我有一个产品需要实现撤消重做功能的要求。

目前我持有一个来自单个 mongo 集合的巨大对象。

伪结构:

{
  cart:{
    products:[
      {
        name: "Watch",
        quantity: 1,
        shippingDate: 123456782,
        text: "lorem ipsum....",
        prices:[
          {
            currency: "USD",
            price: 300
          },
          {
            currency: "GBP",
            price: 220
          }
        ]
      }
    ],
    ...someMoreKeyValuePair
  }
}

现在更新可以发生在任何节点上,例如:添加/修改/删除产品,添加/修改/删除购物车级别数据。

而且结构很大,现在我如何对整个结构上发生的任何更改保持撤消-重做操作。

我应该阅读什么数据结构或设计模式以获得更好的方法来解决这个问题。

更新:

undo-redo 需要持久化在数据库中。我使用的语言是 Javascript-NodeJS

标签: javascriptnode.jsdesign-patternsdata-structuresundo-redo

解决方案


您需要保留更改日志。因此,您的服务器应用程序(nodejs)处理的客户端请求应转换为数据库操作,这些操作 记录更改(像撤消日志一样)并在一个事务中执行它。

然后在适当的时候实现逻辑以清除撤消日志,从该日志中弹出一个操作并执行相反的操作,......等等。

这种撤消日志中的记录将包含 3 到 4 个元素:

  1. 一个动作:“更新”、“插入”或“删除”。后两者主要用于表示数组操作。
  2. 标识应在对象中何处应用更改的路径。该路径将是一个属性数组,例如可以将其编码为点分隔的字符串。
  3. 该位置的旧值(在“更新”或“删除”的情况下),JSON 编码。
  4. 该位置的新值(在“更新”或“插入”的情况下),JSON 编码。

此类记录的示例:

  • ("update", "cart.products.0.name", '"Watch"', '"Watching"')
  • ("delete", "cart.products.prices.1", '{"currency":"GBP","price":220}', null)prices:这表示从数组的索引 1 中删除旧值的操作。通过移动数组值来填补空白,就像splice(index, 1)JavaScript 中的操作一样。
  • ("insert", "cart.products.prices.0", null, '{"currency":"EUR","price":270}'):这表示将新值插入到prices数组中的索引 0 处的操作。如果该索引已经有一个值,它会向右移动,就像splice(index, 0, newvalue)JavaScript 中的操作一样。

这些null值仅表明此参数与该特定操作无关。

上面的示例日志将累积到以下数据,从您提供的示例数据开始:

{
  cart:{
    products:[
      {
        name: "Watching",
        quantity: 1,
        shippingDate: 123456782,
        text: "lorem ipsum....",
        prices:[
          {
            currency: "EUR",
            price: 270
          },
          {
            currency: "USD",
            price: 300
          }
        ]
      }
    ]
  }
}

这样的日志具有撤消操作的所有内容:如果数据被擦除(“更新”、“删除”),您可以从第三个参数中恢复被擦除的数据。


推荐阅读