存储不同版本数据的首选方法是什么?

Jos*_*don 5 language-agnostic

当您编写需要以相同方式读取和处理两个版本数据的应用程序时,构造类来表示该数据的最佳方法是什么.我想出了三个场景:

  1. 共同基础/特定儿童
  2. 数据联盟
  3. 独特的结构

版本1汽车示例

byte DoorCount
int Color
byte HasMoonroof
byte HasSpoiler
float EngineSize
byte CylinderCount
Run Code Online (Sandbox Code Playgroud)

第2版​​汽车

byte DoorCount
int Color
enum:int MoonRoofType
enum:int TrunkAccessories
enum:int EngineType
Run Code Online (Sandbox Code Playgroud)

共同基础/特定儿童

使用此方法,在两个版本的数据之间存在公共字段的基类,并且对于每个版本的数据存在子类.

class Car {
    byte DoorCount;
    int Color;
}

class CarVersion1 : Car {
    byte HasMoonroof;
    byte HasSpoiler;
    float EngineSize;
    byte CylinderCount;
}

class CarVersion2 : Car {
    int MoonRoofType;
    int TrunkAccessories;
    int EngineType;
}
Run Code Online (Sandbox Code Playgroud)

优势

  • OOP范式

弱点

  • 如果发布了删除公共字段的新版本,则必须更改现有子类
  • 一个概念单元的数据在两个定义之间分开,而不是因为任何对自身有意义的分区.

数据联盟

这里,Car被定义为跨所有版本数据的Car字段的并集.

class Car {
    CarVersion version;
    byte DoorCount;
    int Color;
    int MoonRoofType;     //boolean if Version 1
    int TrunkAccessories; //boolean if Version 1
    int EngineType;       //CylinderCount if Version 1
    float EngineSize;     //Not used if Version2
}
Run Code Online (Sandbox Code Playgroud)

优势

  • 嗯......一切都在一个地方.

弱点

  • 强制案例驱动的代码.
  • 删除其他版本或旧版时难以维护.
  • 很难概念化.字段的含义根据版本而变化.

独特的结构

这里的结构彼此之间没有OOP关系.但是,如果/当代码期望以相同的方式处理它们时,接口可以由两个类实现.

class CarVersion1 {
    byte DoorCount;
    int Color;
    byte HasMoonroof;
    byte HasSpoiler;
    float EngineSize;
    byte CylinderCount;
}

class CarVersion2 {
    byte DoorCount;
    int Color;
    int MoonRoofType;
    int TrunkAccessories;
    int EngineType;
}
Run Code Online (Sandbox Code Playgroud)

优势

  • 直截了当的方法
  • 如果添加新版本或删除旧版本,则易于维护.

弱点

  • 这是一种反模式.

有没有更好的方法,我没有想到?很明显,我赞成最后一种方法,但第一种方法更好吗?

Jef*_*ang 1

为什么第三个选项(每个版本都有不同的结构)是一个坏主意或反模式?

如果在公共应用程序/模块中使用两个版本的数据结构 - 它们将必须实现相同的接口。时期。编写两个不同的应用程序模块来处理两个不同版本的数据结构肯定是站不住脚的。底层数据模型极其不同这一事实应该是无关紧要的。毕竟,编写对象的目标是达到实用级别的封装。

当您继续以这种方式编写代码时,您最终应该会发现两个类中的代码相似或冗余的地方。如果将这些通用代码段从各个版本类中移出,您最终可能会得到不仅实现相同接口,而且还可以实现相同基/抽象类的版本类。瞧,您已经找到了“第一个”选项。

我认为这是数据不断变化的环境中的最佳路径。它需要对旧代码进行一些勤奋和“回顾”,但值得享受代码清晰度和可重用组件的好处。

另一个想法:在您的示例中,基类是“Car”。在我看来,基类与它的继承者几乎没有如此“接近”。一组更现实的基类或接口可能是“Versionable”、“Upgradeable”、“OptionContainer”等。仅根据我的经验来说,YMMV。