Fachkonzept - Datenkapselung
Daten kontrolliert zugänglich machen
Datenkapselung schützt die Daten eines Objekts:
Von außen sind sie nur über kontrollierte Zugriffe lesbar oder änderbar.
In Kotlin erfolgt der Zugriff auf Eigenschaften über einen
Getter und – bei var – einen
Setter. Ohne eigene Definitionen erzeugt Kotlin
beide automatisch. Ein gespeicherter Wert liegt im
Backing Field field.
Die drei Standardfälle
Lesen oder Ändern erlauben
Verwende val, wenn ein Wert nach der Erzeugung nicht geändert
werden soll, und var, wenn Änderungen erlaubt sind. Eigene
Getter und Setter sind dafür nicht nötig.
class Spielfigur(val rolle: String, var level: Int)
fun main() {
val held = Spielfigur("Magier", 1)
println(held.rolle) // Lesen
held.level = 2 // Schreiben
// held.rolle = "Krieger" // Fehler: val ist unveränderlich
}
Werte beim Schreiben prüfen
Ein eigener Setter kann ungültige Werte zurückweisen oder ersetzen. Das
Backing Field wird darin über field angesprochen.
class Mensch {
var alter: Int = 0
set(wert) {
if (wert >= 0) field = wert
}
}
fun main() {
val mensch = Mensch()
mensch.alter = 12
mensch.alter = -5 // bleibt 12
println(mensch.alter)
}
Bei einem negativen Wert bleibt hier der bisherige Wert erhalten.
Werte beim Lesen berechnen
Ein Getter kann einen Wert aus anderen Eigenschaften ableiten. Eine solche Eigenschaft braucht kein eigenes Backing Field und ist hier schreibgeschützt.
class Rechteck(val breite: Double, val hoehe: Double) {
val flaeche: Double
get() = breite * hoehe
}
fun main() {
val rechteck = Rechteck(2.0, 3.0)
println(rechteck.flaeche) // 6.0
}
Abgeleitete Eigenschaften werden im Klassendiagramm mit einem vorangestellten
/ gekennzeichnet.
Optionale Vertiefungen
Setter auch beim Erzeugen aufrufen
Ein Konstruktorparameter mit val oder var erhält
keinen benutzerdefinierten Setter. Nimm den Startwert als normalen Parameter
entgegen und weise ihn in init der Eigenschaft zu:
class Mensch(startAlter: Int) {
var alter: Int = 0
set(wert) { if (wert >= 0) field = wert }
init { alter = startAlter } // ruft den Setter auf
}
fun main() {
val mensch = Mensch(-5)
println(mensch.alter) // 0
}
Interne Details verbergen
private beschränkt den Zugriff auf die Klasse. Das gilt für
Eigenschaften und interne Hilfsmethoden.
class Tresor {
private val pin = 1234
fun pruefePin(eingabe: Int) = eingabe == pin
}
fun main() {
val tresor = Tresor()
println(tresor.pruefePin(1234))
}
Nur das Ändern beschränken
Mit private set bleibt eine Eigenschaft von außen lesbar,
kann aber nur innerhalb der Klasse geändert werden. So lassen sich zusammengehörige
Werte über eine Methode gemeinsam ändern.
class Timer {
var min: Int = 0
private set
var max: Int = 0
private set
fun setzeBereich(neuesMin: Int, neuesMax: Int) {
if (neuesMin >= 0 && neuesMin < neuesMax) {
min = neuesMin
max = neuesMax
}
}
}
fun main() {
val timer = Timer()
timer.setzeBereich(10, 20)
println("${timer.min} bis ${timer.max}")
}