可能与我的问题类似但略有不同,可能并不相关。
我需要将共享逻辑移动到超类中,问题在于我无法使用泛型T的copy方法。我找到了这个解决方法:
实体:
data class MyEntity(
val id: String,
val createdAt: Instant,
val updatedAt: Instant
)
抽象泛型仓储库:
abstract class GenericRepository<T> {
abstract val copyFn: KCallable<T>
fun add(obj: T) {
val instanceParameter = copyFn.instanceParameter!!
val idParameter = copyFn.findParameterByName("id")!!
val copy = copyFn.callBy(
mapOf(
instanceParameter to obj,
idParameter to "new id"
)
)
}
}
更干净、更通用的抽象泛型仓储版本:
abstract class BetterGenericRepository<T> {
abstract val copyFn: KCallable<T>
fun add(obj: T): T {
val instanceParameter = getInstanceParameter()
val idParameter = getParameterByName(instanceParameter, "id")
val updatedAtParameter = getParameterByName(instanceParameter, "updatedAt")
val copy = copyFn.callBy(
mapOf(
instanceParameter to obj,
idParameter to "new id",
updatedAtParameter to Instant.now()
)
)
return copy
}
private fun getInstanceParameter() =
copyFn.instanceParameter
?: throw RuntimeException("${copyFn.returnType} must be Data Class or its method '${copyFn.name}' must have 'instanceParameter' as KParameter")
private fun getParameterByName(instanceParameter: KParameter, name: String) =
copyFn.findParameterByName(name)
?: throw RuntimeException("${instanceParameter.type} must have '$name' property")
}
抽象存储库的具体实现
class MyRepository: BetterGenericRepository<MyEntity>() {
override val copyFn = MyEntity::copy
}
还有一个简单的检查:
fun main() {
val repository = MyRepository()
val entity = MyEntity(
id = "1",
createdAt = Instant.EPOCH,
updatedAt = Instant.EPOCH
)
println(entity)
println(repository.add(entity))
}
结果
MyEntity(id=1, createdAt=1970-01-01T00:00:00Z, updatedAt=1970-01-01T00:00:00Z)
MyEntity(id=new id, createdAt=1970-01-01T00:00:00Z, updatedAt=2020-08-26T13:29:42.982Z)
super.copy
,它不会递归调用copy吗?我将我的命名为copyID
只是为了确保。 - Chad Bingham