2015-10-20 85 views
1

我的项目中有四个域对象。他们有3个共同的属性,即id,姓名和年龄。Java对象相等

public class Domain1 { 
     private String id; 
     private String name; 
     private int age; 
     ... 
} 

public class Domain2 { 
     private String id; 
     private String name; 
     private int age; 
     ... 
} 

public class Domain3 { 
     private String id; 
     private String name; 
     private int age; 
     ... 
} 

public class Domain4 { 
     private String id; 
     private String name; 
     private int age; 
     ... 
} 

domain1并Domain4比较仅基于“id”属性时与其他域(域2,和DOMAIN3 Domain4)相比或与对方。 Domain2和Domain3的比较基于id,名称和年龄,除非彼此相互比较。

对于离,

Domain1 equal Domain2 - equality based on id 
Domain1 equal Domain3 - equality based on id 
Domain1 equal Domain4 - equality based on id 
Domain2 equal Domain3 - equality based on id, name and attribute 
Domain2 equal Domain4 - equality based on id 
Domain3 equal Domain4 - equality based on id 

等等...

如何实现这样一个平等的要求?

+3

我通常会说一个类型的实例等于另一个类型的实例是一个坏主意。我不记得曾经看到那种正确和有用的执行。 –

回答

1

您可以根据您的要求只为overrideequals()方法为这四个域对象。 您可以通过IDE生成它并进行修改以符合您的要求。

编辑:在你的方法,你可以找对象,你要比较的类型:

public boolean equals(Object object){ 
    if(object instancof Domain4) //Specific implementation 
    .... 
} 

然而,像乔恩表示,将违反的Object.Equals的要求。

+0

谢谢@talhouarne。我的要求是,如果我调用domain1.equals(domain2)或domain2.equals(domain1)它应该做基于id的平等。如果我做domain2.equals(domain3),它应该根据id,名称和属性进行平等。我如何在domain2中有两种不同的实现? – user3222372

+0

看到我的编辑.... – ltalhouarne

+0

@talhouarne,我也不喜欢这种方式。有没有其他方法可以更好地实现这一目标?我们不断为我们的项目引入新的领域,所以如果我们能够在这里得到一个好的解决方案将是非常好的。 – user3222372

2

我只是尽量不要这样做。你提出的规则违反Object.equals的要求,特别是:

传递性:对于任何非空引用值x,y和z,如果x.equals(y)返回真和y .equals(z)返回true,那么x.equals(z)应该返回true。

现在考虑您的规则:

Domain1 d1 = new Domain1("id1", "name1", "attribute1"); 
Domain2 d2 = new Domain2("id1", "name1", "attribute1"); 
Domain3 d3 = new Domain3("id1", "name3", "attribute3"); 

现在d2.equals(d1)是真实的(它们匹配的ID)和d1.equals(d3)是真实的(它们匹配的ID),但d2.equals(d3)是假的,因为它们不匹配关于属性和名称。

我不认为我记得在完全不同类型的工作很好地看到平等。试图避免超类/子类关系中的意外已经够难了,但这种情况更糟。

+0

谢谢@Jon的反馈。你是对的,这不是一个正确的平等用例。它在某些情况下就像部分匹配。有没有其他的方式来实现这一点像使用comapreTo或某种模式匹配? – user3222372

+0

@ user3222372:好吧,我们不知道你想用这种非标准匹配来实现什么,这使得很难告诉你如何实现它,除了说“不要这样做”。 –

+0

我基于上面的等式规则对基于对象的域对象应用业务规则。我们需要在一些数据结构中存储这些对象并应用业务规则。 – user3222372

0

也许我不是在这里理解用例,但是你可以试试using a Comparator,然后创建一个ComparableDomain接口,它具有像getType(这会返回Domain1,Domain2等)以及普通getter/setters(for名称,年龄和id),并让您的所有域都实现ComparableDomain。

现在,您可以先比较两个不同的Domain对象,首先询问它们的类型,然后按照您所描述的步骤检查这些字段。

public class DomainComparator implements Comparator<ComparableDomain>{ 

    @Override 
    public int compare(ComparableDomain domain1, ComparableDomain domain2) { 
     //First check domain1 and domain2 are actually ComparableDomain objects 
     if(domain1.getType().equals("Domain1") && domain2.getType().equals("Domain2")){ 
      // Do comparison between d1 and d2 
     } 
     ... 
     elseif(domain1.getType().equals("Domain2") && domain2.getType().equals("Domain3"){ 
      // Do comparison based on id, name and attribute 
     } 

    } 

} 

这可能不是很优雅,但它似乎可以解决问题。或者,也许我只是误解了这个问题。我知道比较器通常用于排序等,但在这种情况下,它可能工作。

+0

谢谢@Acapulco。你正确地理解了这个问题。如果域数量不增长,此解决方案将起作用。我们不断添加新的域名,这种设计将来不会持续。 – user3222372

+0

是的,我认为这很难。另一个更复杂的选项是通过配置文件参数化比较。无论何时创建DomainComparator,都会加载配置文件并设置比较不同类型域的规则。这样你就可以随心所欲地变得灵活。缺点是您需要编写小配置加载程序并确保规则按预期工作等。但是我发现,对于很多问题,具有决定内部组件行为的外部配置文件可能会使事情变得更容易 – Acapulco

+0

所以你可以定义一个类似于状态机的转换表的表,然后你可以在一行和一列(两个域类型)上创建一个十字,以及由该表指定的实际矩阵索引行和列会让你知道究竟要比较什么,或者即使这两个域甚至可以比较开始。这意味着比较规则由行/列交叉确定。现在,这将是一个定义什么样的规则的问题。它可能是一个位图(每个属性要比较1位,所以101可以是比较ID,忽略名称,比较年龄) – Acapulco