Kotlin нулевая безопасность и логические выражения - PullRequest
1 голос
/ 17 апреля 2020

Правильно ли написан мой код или есть другой способ справиться с Kotlin нулевой безопасностью внутри логических выражений?

class AddressSpecification(private val address: Address) : Specification {
    override fun isSatisfiedBy(): Boolean {
        return (address.municipality.isNotBlank()
                && if (address.neighbourhood == null) true else address.neighbourhood.isNullOrBlank()
                && address.postalCode.isNotBlank()
                && address.stateAbbreviation.isNotBlank())
                && if (address.street.apartment == null) true else address.street.apartment > 0

    }
}

Ответы [ 3 ]

1 голос
/ 17 апреля 2020

Ваши нулевые проверки могут быть упрощены.

if (address.neighbourhood == null) true else address.neighbourhood.isNullOrBlank()

может быть просто:

address.neighbourhood.isNullOrBlank()

Причина, по которой работает, заключается в том, что Kotlin функции расширения могут работать на обнуляемых приемниках, и isNullOrBlank определяется таким образом, поэтому нет необходимости заранее проверять наличие нуля.

Кроме того:

if (address.street.apartment == null) true else address.street.apartment > 0

можно переписать как:

address.street.apartment ?: 1 > 0

, который использует оператор Элвиса для возврата к 1, если apartment равен нулю, что делает общее выражение истинным в этом случае.

0 голосов
/ 17 апреля 2020

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)]
}
0 голосов
/ 17 апреля 2020

Такая проверка избыточна:

if (address.neighbourhood == null) true else address.neighbourhood.isNullOrBlank()

Сначала вы проверяете, является ли она нулевой. Если это не ноль, вы проверяете снова, является ли это нуль или пустым. Таким образом, вы можете просто использовать вторую часть address.neighbourhood.isNullOrBlank()

(Кроме того, это то, что вы действительно хотите? Все остальное должно существовать, но окрестности должны быть нулевыми или пустыми?)

Последняя строка может быть свернута в логическое выражение, которое обычно проще написать и понять, чем if / else, когда вы используете if / else для возврата логического значения.

И, наконец, поскольку все, что вы ' Повторная проверка является свойством address, вы можете использовать функцию объема run, чтобы избежать необходимости вводить ее снова и снова.

override fun isSatisfiedBy(): Boolean {
    return address.run {
        municipality.isNotBlank()
            && neighbourhood.isNullOrBlank()
            && postalCode.isNotBlank()
            && stateAbbreviation.isNotBlank())
            && (street.apartment == null || street.apartment > 0)
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...