基于official documentation和此detekt rule,我的理解是,数据类应该用作DTO,并且不应包含任何行为/逻辑。
但是,对于我的域实体(包含数据和行为),我仍然希望具有自动toString
,equals
和解构声明等功能。
我可以使用数据类轻松实现这一点,但是基于上述,在语义上似乎是不正确的:
data class Person(
private var name: String,
val age: Int
) {
fun isAdult() = age >= 18
fun changeName(newName: String) {
this.name = newName
}
}
为此目的使用数据类是天生的错误吗?还有其他方法可以保留这些功能,但同时在语义上正确吗?
我认为有两个重要主题:
不可移植性
我会接受不变性,而在域类中不提供任何突变方法,您可以使用copy
方法来创建具有不同不变属性的新实例。
身份
数据类使用equals方法中在构造函数中声明的所有属性。这意味着它是一个值类,也就是说,它没有身份。它是一个类似于Point(x,y)的值。点Point(1,2)和Point(1,2)的两个实例是无法区分的,如果它们的所有属性都相同,则它们是相同的。]
结论
将常规class
用于域实体,例如User
equals
,hashcode
等。将data class
用于域值,例如Address。只要没有突变,数据类就可以具有功能。