首先,如果你想使用抽象的可验证对象,你需要Validatable
接口:
interface Validatable {
fun validate()
}
您还需要一个代表经过验证的对象的类:
data class Valid<out T : Validatable>(val obj: T) {
init {
obj.validate()
}
fun <U : Any> U?.mustBeValidated(): U = checkNotNull(this) {
"${obj::class.jvmName}.validate() successfully validated invalid object $obj"
}
}
现在您需要Validatable.valid()
有助于创建Valid
实例的函数:
fun <T : Validatable> T.valid(): Valid<T> = Valid(this)
以下是您如何成为自己的RequestModel
人Validatable
:
data class RequestModel(
val description: String?
) : Validatable {
override fun validate() {
requireNotNull(description) { "description must be non null" }
}
}
val Valid<RequestModel>.description get() = obj.description.mustBeValidated()
以下是如何使用它:
val validModel: Valid<RequestModel> = model.valid()
val notNullDescription: String = validModel.description
您还可以使Valid
类inline。由于内联类不能有init
块,init
逻辑被移到工厂方法。并且由于内联类主构造函数应该是public
,构造函数被标记为@Experimental private annotation class ValidInternal
防止非法构造函数使用:
@UseExperimental(ValidInternal::class)
fun <T : Validatable> T.valid(): Valid<T> {
validate()
return Valid(this)
}
@Experimental
private annotation class ValidInternal
inline class Valid<out T : Validatable> @ValidInternal constructor(
// Validatable is used here instead of T
// because inline class cannot have generic value parameter
private val _obj: Validatable
) {
@Suppress("UNCHECKED_CAST") // _obj is supposed to be T
val obj: T
get() = _obj as T
fun <U : Any> U?.mustBeValidated(): U = checkNotNull(this) {
"${obj::class}.validate() successfully validated invalid object $obj"
}
}