我正在尝试使用 Kotlin 和 DDD 实现 ValueObject 基类。由于任何值对象都必须考虑 equals 方法中的所有属性,因此我决定使用反射实现单个方法,因此不需要子类来实现它。
我的ValueObject类如下:
abstract class ValueObject {
override fun equals(other: Any?) = when {
this === other -> true
other !is ValueObject -> false
else -> deepEquals(other)
}
inline fun <reified T : Any> deepEquals(other: T): Boolean {
val fields = T::class.java.declaredFields
println(T::class)
for (field in fields) {
field.isAccessible = true
val thisValue = field.get(this)
val otherValue = field.get(other)
if (thisValue != otherValue && (thisValue == null || !thisValue.equals(otherValue))) {
return false
}
}
return true
}
override fun hashCode() = hashFromReflection()
private fun hashFromReflection(): Int {
val fields = this::class.java.declaredFields
var result = 17
for (field in fields) {
field.isAccessible = true
val value = field.get(this)
result = 31 * result + (value?.hashCode() ?: 0)
}
return result
}
protected abstract fun validate() : Notification
}
我实现了以下代码来测试:
class PhoneNumber (val code: String, val number: String) : ValueObject() {
override fun validate(): Notification {
return Notification()
}
}
fun main() {
val phoneNumber = PhoneNumber("33", "w")
val other = PhoneNumber("3", "w")
println(phoneNumber == other)
println(phoneNumber.deepEquals(other))
}
然而,结果很奇怪。如果我直接调用 deepEquals ,它工作得很好。但如果我使用 == 运算符,它会将 T 视为 ValueObject(而不是 PhoneNumber),找不到声明的字段,并给出错误的结果:
class br.all.domain.common.ValueObject
true
class br.all.domain.common.PhoneNumber
false
我做错了什么?
你似乎用
reified
使这件事变得过于复杂。您可以通过执行 Class
或 this::class.java
来获取对象的 other::class.java
。不需要reified
。
override fun equals(other: Any?): Boolean {
if (this === other) return true
// note that you should also check this::class.java != other::class.java!
if (other == null || this::class.java != other::class.java) return false
val fields = other::class.java.declaredFields
for (field in fields) {
field.isAccessible = true
val thisValue = field.get(this)
val otherValue = field.get(other)
if (thisValue != otherValue && (thisValue == null || !thisValue.equals(otherValue))) {
return false
}
}
return true
}
您的代码不起作用的原因是,当您在
ValueObject
中调用deepEquals(other)
时,没有关于equals
特定子类的类型信息。具体化类型参数只是作为 deepEquals<ValueObject>(other)
传递。
此外,您似乎正在重新发明数据类。考虑使用数据类来执行此操作。
abstract class ValueObject {
protected abstract fun validate(): Notification
}
data class PhoneNumber (val code: String, val number: String) : ValueObject() {
override fun validate(): Notification {
// ...
}
}