【问题标题】:design pattern for "save"“保存”的设计模式
【发布时间】:2012-12-02 13:21:49
【问题描述】:

我目前正在研究一种“保存”机制,它允许用户将他正在处理的项目保存在硬盘上。输出将是一个包含各种数据的 XML 文件。
现在我们的项目结构即将发生变化,我们需要编写一个新的 xml 文件(创建一个新的保存方法)。
所以现在挑战来了:保存时我希望用户能够选择他将创建的文件格式(版本 1(旧)或版本 2(新))。
有谁现在如何实现这一目标?周围有合适的设计模式吗?
评论: - 我们保存的数据可以被视为不相关的块,因此实际上很容易将旧块换成新块。 - 事情的全部目标是,在加载旧项目时应该再次可读。 (我假设这可以通过标签来完成,并且在加载时只对标签做出反应?)

【问题讨论】:

  • Strategy 听起来像你想要的。
  • boost::serialization 可用于将对象保存为 xml 格式。
  • 从某种意义上说,这与 Google Protocol Buffers 和 Facebook Thrift 试图解决的问题相同......

标签: c++ xml qt design-patterns save


【解决方案1】:

这听起来像是Strategy 模式的一个很好的应用程序。

您将创建一个抽象基类FileFormat(策略接口),其中包含两个虚函数projectToXmlxmlToProject,它们应该将您的内部项目表示转换为XML,反之亦然。

然后创建两个实现子类FileFormatNewFileFormatLegacy(这些是具体策略)。

然后,您的保存函数将额外需要一个 FileFormat 实例,并调用该对象的相应方法来进行数据转换。您的加载函数可以通过检查 XML 树来选择要使用的策略,以了解它是哪个版本。

当您需要支持另一种文件格式时,您只需创建一个新类,它是 FileFormat 的子类。

cmets交流后的补充

当您将拥有许多差异很小的版本并且您仍想使用策略模式时,您可以将 FileFormat 制作为多种策略的组合:CircleStragegy、RectangleStrategy、LineStrategy 等。在这种情况下,我不会为不同版本的 FileFormat 使用不同的类。我将为每个版本创建一个静态工厂函数,该函数返回一个 FileFormat 以及该版本中使用的 Strategy 对象。

FileFormat FileFormat::createVersion1_0() {
    return new FileFormat(
        new LineStrategyOld(),
        new CircleStrategyOld(),
        new RectangleStragegyOld()
    );
}

FileFormat FileFormat::createVersion1_1() {
    // the 1.1 version introduced the new way to save lines
    return new FileFormat(            
        new LineStrategyNew(),
        new CircleStrategyOld(),
        new RectangleStragegyOld()
    );
}

FileFormat FileFormat::createVersion1_2() {
    // 1.2 uses the new format to save circles
    return new FileFormat(            
        new LineStrategyNew(),
        new CircleStrategyNew(),
        new RectangleStragegyOld()
    );
}

FileFormat FileFormat::createVersion1_3() {
    // 1.3 uses a new format to save rectangles, but we realized that
    // the new way to save lines wasn't that good after all, so we
    // returned to the old way.
    return new FileFormat(            
        new LineStrategyOld(),
        new CircleStrategyNew(),
        new RectangleStragegyNew()
    );
}

注意:在实际代码中,您当然会为策略类名称使用比“旧”和“新”更多的描述性后缀。

【讨论】:

  • 所以基本上每个对象都负责传递 xml 数据?这意味着我不会有一个大型方法收集所有使用公共 getter 和 setter 用于不同成员,而是我会调用一个方法“getAppropriateData()”,我会从对象本身获取数据?使用这种方法,我什至对于两个保存版本之间最细微的变化都需要一个新的具体策略,它调用与上一个相同的所有函数,除了一个微小的变化,对吧?
  • 应始终避免冗余代码。当两种策略非常相似并且仅在一些小细节上有所不同时,要么可以从另一个继承,要么可以将大部分代码移动到基类的公共私有函数中,同时只执行每个派生中真正不同的部分类。
  • 关于如何收集需要通过您的策略保存的数据:我需要知道您的数据是如何构建的,以便对此提出任何建议。当您希望通过为需要保存的所有内容设置 getter 来避免暴露项目类的太多细节时,您可以使用访问者模式来收集数据。 en.wikipedia.org/wiki/Visitor_pattern
  • 首先:感谢所有伟大的提示!第二件事是:想象一下我将创建一个绘图工具。现在我编写了保存函数,其中保存了矩形(通过保存所有 4 个角的坐标)和圆(中心和半径的坐标),我们称之为 Version1。对于下一个版本,我改变了我的结构,现在想将矩形保存一个角、宽度和高度——其余的保留。因此,Version2 可以从 Version1 继承。现在我更改了一个圆圈的保存,因此 Version3 从 Version2 继承,一切都开始搞砸了......
  • 当你有很多版本差异很小并且你仍然想使用策略模式时,你可以让 FileFormat 成为多个策略的组合:一个 CircleStragegy、一个 RectangleStrategy、一个LineStrategy 等。在这种情况下,我不会为不同版本的 FileFormat 使用不同的类。我将为每个版本创建一个工厂方法,该方法返回一个 FileFormat 以及该版本所需的 Strategy 对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-26
  • 2011-07-07
  • 1970-01-01
  • 2013-03-11
相关资源
最近更新 更多