我正在阅读Eric Evans关于DDD的书,我对以下引用有疑问。如果不使用属性,如何制作equals()
方法?我正在使用JPA,并且我有一个唯一的id属性,但在实际持久保存实体之前不会设置。所以你会怎么做?我已经基于属性实现了equals方法,并且我理解为什么你不应该因为它在我的项目中失败。
关于实体的部分:
当一个对象通过其身份而不是它的身份来区分时 属性,使其主要在模型中定义。保持 类定义简单,注重生命周期的连续性和 身份。定义一种区分每个对象的方法,无论如何 它的形式或历史。警惕要求匹配的要求 对象按属性。定义一个保证的操作 为每个对象产生一个独特的结果,可能是通过附加一个 保证唯一的符号。这种识别方式可以 来自外部,或者它可能是由...创建的任意标识符 对于系统,但它必须对应于身份 模型中的区别。模型必须定义它意味着什么 同样的事情。
http://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215
答案 0 :(得分:2)
夫妻接近可能:
使用商家密钥。这是最“符合DDD”的方法。仔细查看域和业务要求。例如,您的企业如何识别客户?他们使用社会安全号码还是电话号码?如果它是基于纸张的(没有计算机),您的企业将如何解决这个问题?如果没有自然业务密钥,请创建代理。选择最终的商家密钥,并在equals()
中使用它。 DDD书中有一节专门讨论这个具体问题。
对于没有自然业务键的情况,您可以生成UUID。这在分布式系统中也具有优势,在这种情况下,您不需要依赖集中(并且可能不可用)的资源(如数据库)来生成新的ID。
还可以选择依赖默认equals()
实体类。它会比较两个内存位置,在大多数情况下就足够了,因为Unit Of Work(Hibernate Session)保留所有实体(这个ORM模式称为Identity Map)。这是不可靠的,因为如果你使用不限于一个Hibernate会话范围的实体(想想线程,分离的实体等)它会破坏
有趣的是,'官方'DDD示例使用了一个非常轻量级框架,其中每个实体类都是使用一种方法从Entity接口派生的:
boolean sameIdentityAs(T other)
// Entities compare by identity, not by attributes.
答案 1 :(得分:1)
如果对象尚未持久化,那么根据属性比较2个对象是否有任何伤害?
我不确定为什么这会在你的项目中失败,但根据我的经验,如果你的属性不是最终的,那么基于属性的比较几乎总是很滑。这意味着,现在相同的2个对象在某些时候可能不相等。这真是太糟了。
鉴于大多数Java类与其访问器一起编写,等于比较属性被认为是一个坏主意。
但是,我可能首先检查ID字段是否为空。如果它为null,我会回到属性比较。如果它不为null,那么只需使用它而不做其他任何事情。这有意义吗?
答案 2 :(得分:1)
给定Person
类包含属性name
,surname
。当21岁的人更改其名称时,它仍然是同一个人(等于给出true
)?
如果你在属性上写等于基础,那么,它就不是同一个人,所以在我看来,最好的方法是在它们的业务标识符上测试实体的相等性(在整个实体生命周期中是唯一的和不可变的)。
答案 3 :(得分:0)
另一种解决方案可能是在您的实体中使用UUID
字段。
在这种情况下,您可以使用UUID
作为主键或仅使用等号。
@Entity
public class YourEntity{
@Id
private String uuid = UUID.randomUUID().toString();
// getter only...
}