首页 > 解决方案 > 在 C++ 中为许多类设计持久性模型同时确保遵循 SOLID 的最佳方法是什么?

问题描述

我已经在网上搜索了有关如何有效地为 C++ 类设计持久性模型的特定设计信息,但我发现不足。所以我决定在这里问。

假设我有 4 个课程:

A级

B类

C类

类坚持

我想使用“Persist”类将 A、B 和 C 类持久保存到磁盘,这样一个文件包含每个类的配置信息:

my_module.json
{
  A {
    ...
  },
  B {
    ...
  },
  C {
    ...
  }
}

我的问题是,按照 SOLID 原则进行设计的最佳方法是什么?

例如,单一责任原则建议一个类应该只有一种责任(或只有一个改变的理由),而得墨忒耳法则建议类之间尽可能少地了解彼此。

那么:

1)一个类应该知道如何序列化自己,还是已经违反了单一职责?

2)如果我使用像“cereal”这样的第三方库来序列化“A类”,我需要为“A类”的内部成员添加标签,以向引擎展示它应该如何序列化。这增加了“A类”和第三方引擎之间的耦合,这一定很糟糕吧?

3) 我是否应该改用中间类,将对象从“A 类”转换为具有第三方库可以理解的适当标签的对象?这从“A 类”中删除了任何关于序列化的知识,但它增加了更多的复杂性和更多的类。

4) 班级应该知道持久性模块吗?尝试序列化时这是否现实?如果是这样,该类应该如何通知持久性模块状态已经改变并且是时候持久化了?或者持久性模块是否应该简单地定期轮询对象以获取新配置?

我对 OO 还很陌生,但很感兴趣。类之间交互的细节将非常有帮助。谢谢。

标签: c++persistencesolid-principles

解决方案


通常在软件工程中,决策不是关于原则,而是关于权衡。

1 - 它违反了单一职责,但在 C++ 中你没有太多选择。该语言本身不支持运行时反射,也不支持虚拟构造函数/类工厂。没有这两个特性,没有对象序列化自己就很难实现对象序列化。“非常困难”是指它需要外部工具或大量宏/模板,IMO 长期支持非常昂贵。

2 - 它增加了耦合,增加了很多复杂性(你必须支持你正在使用的任何 3rd 方库),但是如果你需要同时支持多种不同的序列化格式,例如 JSON、XML 和二进制,它仍然可能是一件好事。

3 - 取决于,但我会说“不”。中间表示的好格式是类似于 DOM 树的东西,你会浪费太多的 CPU 时间来构建它,因为太多的小 RAM 分配和指针追逐。如果出于某种原因您想要设计和支持定义良好的中间表示,我会将其构建为一对事件驱动的接口(一个读者另一个作者),请参阅SAX以获得灵感。

4 — 大多数序列化库的设计使得保存/加载是一个一次性的过程。原因是大多数现代通用序列化格式(XML、JSON、大多数二进制格式)不支持更新。无论如何,您都必须写出完整的文件。只有当存储格式支持部分更新时,通知才会带来价值,例如,如果您在 [嵌入式] 数据库中保存/加载,而不仅仅是在 JSON 文件中。通常的做法是,每次完成对对象的修改后,从外部手动调用 save。使用自动保存很容易浪费太多的 IO 带宽和 CPU 时间在一些不一致的中间状态下写入对象。


推荐阅读