当您编写需要以相同方式读取和使用两个版本数据的应用程序时,构造类来表示该数据的最佳方法是什么。我想出了三个场景:
版本1汽车示例
byte DoorCount
int Color
byte HasMoonroof
byte HasSpoiler
float EngineSize
byte CylinderCount
第2版车
byte DoorCount
int Color
enum:int MoonRoofType
enum:int TrunkAccessories
enum:int EngineType
共同基础/特定儿童
使用此方法,两个版本的数据之间存在公共字段的基类,并且每个版本的数据都有一个子类。
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;
}
优势
缺点
数据联盟
这里,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
}
优势
缺点
独特的结构
这里的结构彼此之间没有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;
}
优势
缺点
有没有更好的方式我没想到?很明显,我赞成最后一种方法,但第一种方法更好吗?
答案 0 :(得分:1)
为什么第三种选择,每个版本的不同结构,坏主意或反模式?
如果在通用应用程序/模块中使用两个版本的数据结构 - 它们必须实现相同的接口。期。编写两个不同的应用程序模块来处理两个不同版本的数据结构肯定是站不住脚的。基础数据模型极为不同的事实应该是无关紧要的。毕竟,编写对象的目标是实现一个实际的封装级别。
当您继续以这种方式编写代码时,您最终应该找到两个类中的代码相似或冗余的位置。如果从各种版本类中移出这些常见的代码片段,最终可能最终得到的版本类不仅可以实现相同的接口,还可以实现相同的基类/抽象类。瞧,你已经找到了通向“第一”选择的方式。
我认为这是不断发展的数据环境中的最佳途径。它需要一些勤奋并且在旧代码上“后面”,但值得代码清晰度和可重用组件的好处。
另一个想法:在你的例子中,基类是“Car”。在我看来,几乎没有人证明基类是如此“接近”它的继承者。一组更实际的基类或接口可能是“Versionable”,“Upgradeable”,“OptionContainer”等。只是根据我的经验,YMMV。
答案 1 :(得分:1)
使用第二种方法并使用接口增强它。请记住,您可以实现多个接口“版本”,这使您具有向后兼容的能力!我希望你能得到我的意思;)
答案 2 :(得分:1)
遵守以下要求:
需要以相同方式读取和处理两个版本数据的应用程序
我想说最重要的是你通过数据抽象层汇集所有逻辑,这样你的逻辑就不必关心你是使用版本1,2还是 n of the data。
实现此目的的一种方法是只拥有一个数据类,这是数据的最“缓存”版本。基本上,它会有MoonRoofType
,但不会HasMoonRoof
,因为可以推断出来。这个类也不应该有任何过时的属性,因为它取决于数据抽象层来决定默认值应该是什么。
最后,您将拥有一个根本不关心数据版本的应用程序。
对于数据抽象层,您可能希望也可能不希望每个版本都有数据类。最有可能的是,对于每个版本的数据结构,您只需要一个类,其中Save
和Load
方法用于存储/创建应用程序逻辑使用的数据实例。