标题可能看起来令人困惑,但用几句话来形容这个问题并不容易。让我解释一下情况:
我们有一个Web应用程序项目和一个计算引擎项目。 Web应用程序收集用户输入并使用引擎生成一些结果,并向用户表示。用户输入,引擎输出和其他数据都将使用JPA持久保存到DB。
引擎输入和输出由树结构中的对象组成,例如:
Class InputA {
String attrA1;
List<InputB> inputBs;
}
Class InputB {
String attrB1;
List<InputC> inputCs;
}
Class InputC {
String attrC1;
}
引擎输出的风格类似。
我们希望保留额外字段,因此看起来像:
Class InputBx extends InputB{
String attrBx1;
}
Class InputCx extends InputC{
String attrCx1;
}
在Java OO世界中,我们可以在InputA中存储InputBx列表,并且由于继承而在InputBx中存储InputCx列表。
但是在使用JPA来持久化扩展对象时我们遇到了麻烦。
首先,它需要引擎项目使其类成为JPA实体。发动机本身工作正常,它接受正确的输入并产生正确的输出。当另一个项目试图坚持模型时,迫使他们的模型成为JPA实体并不好闻。
其次,当使用InputA作为条目时,JPA不接受继承的对象。从JPA的角度来看,它只知道InputA包含一个InputB列表,并且不能在InputA对象中持久存储/检索InputBx列表。
当试图解决这个问题时,我们提出了2个想法,但没有人满意我们:
想法1: 使用组合代替继承,所以我们仍然保留原始的InputA,它的树结构包括InputB和InputC: Class InputBx{
String attrBx1;
InputB inputB;
}
Class InputCx{
String attrCx1;
InputC inputC;
}
因此可以平滑地检索原始输入对象树,并且需要使用树中的InputB和InputC对象作为引用来检索InputBx和InputCx对象。
好处是,无论对原始输入类树的结构做了哪些更改(例如更改属性名称,在类中添加/删除属性),扩展类InputBx和InputCx及其属性都会自动同步。
缺点是这种结构增加了对数据库的调用,并且该模型在应用程序(后端和前端)中都不易使用。每当我们需要InputB或InputC的相关信息时,我们需要手动编码来搜索InputBx和InputCx的相应对象。
想法2: 手动创建镜像类以形成原始输入类的类似结构。所以我们创建了: Class InputAx {
String attrA1;
List<InputBx> inputBs;
}
Class InputBx {
String attrB1;
List<InputCx> inputCs;
String attrBx1;
}
Class InputCx {
String attrC1;
String attrCx1;
}
我们可以将其用作Web应用程序的模型,以及JPA实体。这是我们可以得到的:
现在引擎项目可以自由设置,它不需要绑定其他项目如何持久保存这些输入/输出对象。发动机项目现在是独立的。
JPA持久性非常流畅,不需要额外调用数据库
后端和前端用户界面只需使用此模型即可轻松获取原始输入对象和相关信息。当尝试使用引擎执行计算时,我们可以使用映射机制在原始对象和扩展对象之间进行传输。
缺点也很明显:
类结构中存在重复,从OO的角度来看,这是不希望的。
当将其视为DTO以减少数据库调用时,可以在本地传输中使用DTO时声明为反模式。
结构不会自动与原始模型同步。因此,如果对原始模型进行任何更改,我们也需要手动更新此模型。如果一些开发人员忘记这样做,将会有一些不容易找到的缺陷。
我正在寻找以下帮助:
是否有任何现有的良好/最佳实践或模式可以解决我们遇到的类似情况?或者我们应该避免的任何反模式?欢迎参考网络文章。
如果可能,您可以从OO设计,持久性实践,您的经验等方面对想法1和想法2发表评论。
我将非常感谢你的帮助。