我想比较两个相似的对象结构并列出差异

时间:2019-03-13 15:43:53

标签: java design-patterns data-structures

我有两个复杂的对象。我想比较两个相似的对象结构并列出差异。我在所有论坛中搜索,没有正确的解决方案。

每个人都在建议反射方法。反射方法没有帮助我,我尝试了一下。我的对象结构太复杂了。

以下是我的对象结构。列表中包含的对象在其他列表中的顺序可能不同。一个列表可能有该对象,另一个对象可能没有该列表。

结构:

对象
    -Field
    -Field
    -Field
    列表
     -对象
     -object
     -object
        -列表
           -object
           -Field
            -Field
           -对象
            -Field
            -Field
    -Field
    -Field
    -列表
    -object
    -Field
    -Field
    -对象
               -Field
               -Field

3 个答案:

答案 0 :(得分:1)

Reflection API

我仍然建议您调查Java Reflection。参见Wikipedia

例如,如果属性本身是对象,则可以使用Reflection进行递归调用,从而通过相同的方法输入它。

public void determineObjectStructure (Object o) {

    Field[] fields = o.getClass().getDeclaredFields();
    for (Field field : fields) {
        // Check Type of field

        // If not primitive -> determineObjectStructure()

        // create Representation
        }
    }

然后,您可以手动创建一个包含以下内容的“复杂对象结构”表示形式:带有以下内容的列表:

  

levelInComplexObject |对象

然后,可以使用最终列表与从不同对象创建的列表进行比较,并且可以在不同组织级别上比较其结构。

答案 1 :(得分:0)

我同意您对复杂对象的反映方式会变得有些复杂。我也有类似的用例,其中需要比较两个对象,而且我的对象也非常复杂(太多不同类型的字段和关联链)。

因此,进行了过多的搜索,找到了很多解决方案,包括反射方法,JSON比较,但是我最喜欢Job的最有希望的框架是Javers

一个简单的例子可能是:

@Test
public void shouldCompareTwoEntities() {
  //given
  Javers javers = JaversBuilder.javers()
          .withListCompareAlgorithm(LEVENSHTEIN_DISTANCE)
          .build();

  Employee frodoOld = EmployeeBuilder.Employee("Frodo")
          .withAge(40)
          .withPosition("Townsman")
          .withSalary(10_000)
          .withPrimaryAddress(new Address("Shire"))
          .withSkills("management")
          .withSubordinates(new Employee("Sam"))
          .build();

  Employee frodoNew = EmployeeBuilder.Employee("Frodo")
          .withAge(41)
          .withPosition("Hero")
          .withBoss(new Employee("Gandalf"))
          .withPrimaryAddress(new Address("Mordor"))
          .withSalary(12_000)
          .withSkills("management", "agile coaching")
          .withSubordinates(new Employee("Sméagol"), new Employee("Sam"))
          .build();

  //when
  Diff diff = javers.compare(frodoOld, frodoNew);

  //then
  assertThat(diff.getChanges()).hasSize(9);
}

javers.compare(frodoOld, frodoNew)接受两个对象并进行比较并报告差异。在您的情况下,对象具有列表,并且列表中的元素可以采用不同的顺序,在这种情况下,Javers将它们报告为差异。如果要忽略元素的顺序,则在将对象馈送到Javers之前,可以对列表进行排序,然后进行比较。

您可以看看JaVers Documentation

最简单的示例是:

Person pOld = new Person ();
pOld.setName("Foo"):

Person pNew = new Person ();
pNew.setName("Bar"):

Diff diff = javers.compare(pOld, pNew);

diff.getChanges()将给出差异列表。

答案 2 :(得分:0)

ANTLR

ANTLR project是一组用于分析源代码的复杂工具。参见Wikipedia

您编写了定义编程语言规则的语法。对于Java,这已经完成。您可以下载Java语言的开源语法.g4文件。

您将此语法输入到ANTLR中。语法分析器可以识别源代码文件的单词,语法分析器可以识别源代码文件的短语和语句。

您编译这些生成的源文件。然后输入您的Java源文件。出现了抽象语法树,它是表示Java源代码内容的数据结构。您可以轻松地走到那棵树上,随身收集零件(类名,成员变量,方法,参数,局部变量等)。

通过使用ANTLR生成的更多源代码,走路树很容易。这段代码使用了Listener和Visitor模式,因此您可以仅覆盖感兴趣的部分的几种方法。

ANTLR是开源且免费的。

请参阅由ANTLR的主要创建者Terence Parr撰写的标题为The Definitive ANTLR 4 Reference的优秀指南和参考书。