Po spędzeniu prawie pełny rok pisząc Kotlin codziennie Odkryłam, że robi to z klas danych jest zła praktyka. Są to 3 ważne podejścia do tego i po tym, jak wytłumaczę, dlaczego podejście, które sugerują inni ludzie, jest złe.
Wyraź swoją logikę biznesową, która tworzy data class
zmieniać wartość jako 0 lub większa przed wywołaniem konstruktora ze złych wartości. Jest to prawdopodobnie najlepsze podejście w większości przypadków.
Nie należy używać . Użyj zwykłego class
i niech Twoje IDE wygeneruje dla Ciebie metody equals
i hashCode
(lub nie, jeśli ich nie potrzebujesz). Tak, będziesz musiał go ponownie wygenerować, jeśli którakolwiek z właściwości zostanie zmieniona na obiekcie, ale pozostawisz całkowitą kontrolę nad obiektem.
class Test(value: Int) {
val value: Int = value
get() = if (field < 0) 0 else field
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Test) return false
return true
}
override fun hashCode(): Int {
return javaClass.hashCode()
}
}
utworzyć dodatkową bezpieczną nieruchomości na obiekt, który robi to, co chcesz zamiast prywatną wartości, która jest skutecznie nadpisane.
data class Test(val value: Int) {
val safeValue: Int
get() = if (value < 0) 0 else value
}
Złe podejście inne odpowiedzi sugeruje:
data class Test(private val _value: Int) {
val value: Int
get() = if (_value < 0) 0 else _value
}
Problem z tego podejścia jest to, że nie są naprawdę data classes przeznaczona do zmiany danych, takich jak ten. Są tak naprawdę tylko do przechowywania danych. Przesłonięcie gettera dla takiej klasy danych oznaczałoby, że Test(0)
i Test(-1)
nie będą miały siebie nawzajem equal
i będą mieć różne hashCode
s, ale po wywołaniu .value
, będą miały taki sam wynik. Jest to niespójne i chociaż może działać dla ciebie, inne osoby w twoim zespole, które widzą, że jest to klasa danych, mogą przypadkowo nadużyć, nie zdając sobie sprawy, jak to zmieniłeś/sprawiłeś, że nie działała zgodnie z oczekiwaniami (tj. Takie podejście nie byłoby ". t działa poprawnie w Map
lub Set
).
Należy rozważyć zmianę struktury kodu tak, aby wartości ujemne były konwertowane na 0, gdy klasa jest instancjonowana, a nie w pobierającym. Jeśli zastąpisz gettera w sposób opisany w poniższej odpowiedzi, wszystkie inne generowane metody, takie jak equals(), toString() i dostęp do komponentów, będą nadal używać oryginalnej wartości ujemnej, co prawdopodobnie doprowadzi do zaskakującego zachowania. – yole