IMO самая элегантная проверка данных производится с помощью «Шаблон валидатора». Существует множество версий шаблона, но основная идея заключается в том, что вы используете общую схему проверки для всех объектов. Таким образом, все ясно и аккуратно. Любой, кто видит код, может точно понять, каковы правила проверки.
Чем больше проверок необходимо выполнить для объекта, тем лучше он подходит для шаблона Validator.
Вот пример я создал шаблон validator-i sh, сначала несколько общих определений:
data class Error(val reason: String, val path: String)
class Address(
val municipality: String,
val neighbourhood: String
)
abstract class Validator<T>(val toValidate: T) {
abstract fun validate(): List<Error?>
}
Теперь (частичная) реализация валидатора (это покажет вам идею):
class AddressValidator(toValidate: Address) : Validator<Address>(toValidate) {
override fun validate(): List<Error?> {
return listOf(
this::isMunicipalityValid,
this::isNeighbourhoodValid
)
.asSequence()
.map { it(toValidate) }
.filterNotNull()
.toList()
}
fun isMunicipalityValid(address: Address): Error? =
if (address.municipality.isBlank()) Error("municipality is blank", "address.municipality")
else null
fun isNeighbourhoodValid(address: Address): Error? =
if (address.neighbourhood.isBlank()) Error("neighbourhood is blank", "address.neighbourhood")
else null
}
А теперь запустите пример:
fun main() {
var address = Address(
municipality = "municipality",
neighbourhood = "neighbourhood"
)
println(AddressValidator(address).validate()) // => []
var address2 = Address(
municipality = "",
neighbourhood = "neighbourhood"
)
println(AddressValidator(address2).validate()) // => [Error(reason=municipality is blank, path=address.municipality)]
}