kotlin - 如何在 Kotlin 中实现域实体?
问题描述
根据官方文档和这个detekt 规则,我的理解是数据类应该用作 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
方法创建具有不同不可变属性的新实例。
身份
Data 类使用 equals 方法的构造函数中声明的所有属性。这意味着它是一个值类,即它没有标识。它是一个类似于 Point(x,y) 的值。两个实例 Point(1,2) 和 Point(1,2) 无法区分。如果它们的所有属性都相同,则它们是相同的。
结论
class
对像User这样的域实体使用正则。使用定义实体身份的属性来实现equals
,hashcode
等。将 adata class
用于域值,例如Address。只要数据类没有突变,数据类就可以具有功能。
在你的情况下,我会实现类似的东西:
data class Address(val streetName: String)
class Person(
val id: Int,
val name: String,
val age: Int,
val address: Address
) {
fun isAdult() = age >= 18
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Person
if (id != other.id) return false
return true
}
override fun hashCode(): Int {
return id
}
fun copy(
id: Int = this.id,
name: String = this.name,
age: Int = this.age,
address: Address = this.address) = Person(id, name, age, address)
override fun toString(): String {
return "Person(id=$id, name='$name', age=$age, address=$address)"
}
}
fun main() {
val personA = Person(123312, "Person A", 17, Address("Street 1"))
println(personA.isAdult())
println(personA.age)
val olderPersonA = personA.copy(age = 18)
println(olderPersonA.isAdult())
println(olderPersonA.age)
}
编辑:正如你所说,可以选择使用数据类并且只覆盖等于和哈希码,但我不确定它在语义上是否正确。对此的评论表示赞赏。
data class Person(
val id: Int,
val name: String,
val age: Int,
val address: Address
) {
fun isAdult() = age >= 18
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Person
if (id != other.id) return false
return true
}
override fun hashCode(): Int {
return id
}
}
推荐阅读
- c# - WCF 防止 NetNamedPipeBinding 超时
- ssl - Wso identityserver 5.2.0 无法调用使用客户端证书保护的联合 oidc 身份验证器
- javascript - Ruby on Rails - 将文本字段与选择结合起来?
- javascript - 如何将 Base 64 图像分享到 Facebook
- python - Pandas,如何将复杂视图保存在变量中
- javascript - 如何使用 React.js 在 Safari 上的隐藏元素上触发 .click()?
- perl - 如何在单元测试中打印哈希键?
- python-3.x - Kivy 中的可滚动动态网格布局
- java - 如何在 Intellij IDEA 中使用 openjfx-11 存档?
- docusignapi - DocuSign 登录 API 超时错误