s n h m r u

Minimallogo des digitalen Schulbuchs inf-schule.de. Schriftzug in Zustandsübergangsdiagramm eines endlichen Automaten.

s n h m r u
i

Setter

Zugriff auf Attribute limitieren

Wir haben gesehen, dass es zu Problemen führen kann, wenn man uneingeschränkten Zugriff auf die Attribute einer Klasse hat. Es gibt verschiedene Möglichkeiten, um den Zugriff auf Attribute einzuschränken. Das Begrenzen des Zugriffs erreicht man mit Hilfe des Konzepts der Datenkapselung. Man kann dabei unterschiedlich stark einschränken, wie man auf Attribute zugreifen kann. Es ist z.B. möglich, den schreibenden oder lesenden Zugriff zu steuern, oder sogar Attribute komplett zu verstecken, so dass man gar nicht mehr auf sie außerhalb der Klasse zugreifen kann.

Standard-Setter

Wenn man ein Attribut definiert, ergänzt der Compiler automatisch einen sogenannten Setter, der den schreibenden Zugriff auf das Attribut steuert. Du siehst den Standard-Setter nicht in dem von dir geschriebenen Code, aber er wird beim Übersetzen in das ausführbare Programm automatisch hinzugefügt.

Ein Setter sieht so ähnlich aus wie eine Methode. In einigen Sprachen schreibt man dafür tatsächlich eine Methode, in Kotlin gibt es eine spezielle Syntax für den Setter. Den Standard-Setter würde man in Kotlin so schreiben:

class Timer {
    var min: Int = 0
        set(value) {
            field = value
        }
    
    // Rest der Klasse ...
}

fun main() {
    val timer = Timer()
    timer.min = 5 // Hier wird automatisch der Setter aufgerufen
    println(timer.min)
}

Aufgabe 1

(a) Beschreibe den Aufbau eines Setters in Kotlin. Experimentiere dazu mit dem obigen Code. Versuche z.B. value oder field umzubenennen oder ändere die Formatierung wie z.B. die Einrückung oder Zeilenumbrüche.

(b) Ändere den Setter so ab, dass das Attribut min unabhängig von dem Wert, der ihm zugewiesen wird, immer auf 20 gesetzt wird. (Das ist natürlich nicht sinnvoll, aber es soll zeigen, wie ein Setter funktioniert.)

Schreibenden Zugriff auf Attribute steuern

Um zu verhindern, dass Attribute unsinnig verändert werden können, kannst du den Setter so anpassen, dass er den neuen Wert überprüft, bevor er ihn tatsächlich in das Attribut schreibt.

class Timer {
    var min: Int = 0
        set(value) {
            if (value < 0) {
                field = 0
            } else {
                field = value
            }
        }
}

fun main() {
    val timer = Timer()
    timer.min = -5
    println(timer.min)
}

Aufgabe 2

(a) Beschreibe die Änderungen des Setters im Vergleich zum Standard-Setter. Formuliere eine Vermutung, welche Ausgabe das obige Programm erzeugt, und überprüfe deine Vermutung, indem du das Programm ausführst.

(b) Ergänze im obigen Beispielprogramm das Attribut max und schreibe einen Setter, der sicherstellt, dass max immer größer oder gleich min ist. Wenn der neue Wert für max zu klein ist, soll er auf den aktuellen Wert von min gesetzt werden.

(c) Ändere die Implementierung der beiden Setter so ab, dass sie Änderungen bei sinnvollen Werten erlauben, unsinnige Werte aber nicht anpassen, sondern einfach ignorieren.

Komplexere Bedingungen

In den obigen Settern haben wir einfache Bedingungen formuliert, die nur einen Vergleich enthalten, z.B. value < 0 oder value >= min. Manchmal möchte man komplexere Bedingungen formulieren, die z.B. dann wahr sind, wenn mehrere einfache Bedingungen gleichzeitig erfüllt sind, oder wenn mindestens eine von mehreren einfachen Bedingungen erfüllt ist. Dafür gibt es logische Operatoren. In Kotlin gibt es die logischen Operatoren && (logisches Und), || (logisches Oder) und ! (logisches Nicht). Mit diesen Operatoren kannst du komplexe Bedingungen formulieren, z.B.:

fun main() {
    val zahl1 = 2
    val zahl2 = 5

    if (zahl1 == zahl2 && zahl1 == 6) {
        println("Glückwunsch, du hast einen Sechserpasch gewürfelt!")
    }

    if (zahl1 == 6 || zahl2 == 6) {
        println("Glückwunsch, du hast mindestens eine Sechs gewürfelt!")
    }

    if (!(zahl1 == zahl2)) {
        println("Leider Pech gehabt, die Zahlen sind unterschiedlich.")
    }
}

Logische Operatoren kannst du natürlich nicht nur in Settern verwenden, sondern überall dort, wo du Bedingungen formulieren möchtest.

Aufgabe 3

(a) Ändere im obigen Beispielprogramm die Werte von zahl1 und zahl2, so dass jede der Bedingungen im obigen Programm einmal erfüllt ist.

(b) Passe den Setter für max so an, dass nur Werte akzeptiert werden, die größer oder gleich dem aktuellen Wert von min und kleiner oder gleich 60 sind, damit die Zeitspanne des Timers nicht zu groß wird.

Aufgabe 4

Entscheide wie du die Setter für die Attribute min und max am sinnvollsten empfindest. Passe den Timer im BlueJ-Projekt entsprechend an und teste ihn.

Alternativ zur Version in BlueJ kannst du die Online-Version unten nutzen.

class Timer {
    var min: Int = 0
    var max: Int = 0

    fun starten() {
        // Den Inhalt dieser Methode musst du nicht verstehen.
        // Du musst nur wissen, dass die Methode den Timer startet.
        val bis = if (max <= min) max else min + java.util.Random().nextInt(max - min)

        for (i in 0 until bis) {
            try {
                Thread.sleep(1000)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

        println("Timer abgelaufen!")
    }
}

fun main() {
    val timer = Timer()
    // Hier solltest du den Timer noch testen
}

Suche

v
100.123.3.1.2 Setter
Kopieren durch Anklicken

Rückmeldung geben