Menu
Coddy logo textTech

Companion-Objekte

Teil des Abschnitts Objektorientierte Programmierung der Kotlin-Journey von Coddy. Lektion 13 von 57.

Einige Mitglieder gehören zur Klasse als Ganzes und nicht zu einer einzelnen Instanz. Kotlin legt sie in einem companion object innerhalb der Klasse ab, und du rufst sie über den Klassennamen auf:

class Temperature(val celsius: Double) {
    companion object {
        fun fromFahrenheit(f: Double) = Temperature((f - 32) * 5 / 9)
    }
}

Innerhalb von main:

val boiling = Temperature.fromFahrenheit(212.0)
println(boiling.celsius)

Ausgabe:

100.0

fromFahrenheit ist eine Fabrikfunktion: eine Funktion, die Instanzen erstellt. Im Gegensatz zu einem Konstruktor hat sie einen beschreibenden Namen und kann statt eines Objekts null zurückgeben. Mit einem private constructor ist die Fabrik der einzige Zugang, sodass sie die Eingabe zuerst prüfen und bereinigen kann:

class Username private constructor(val text: String) {
    companion object {
        fun of(raw: String): Username? {
            val clean = raw.trim().lowercase()
            return if (clean.length in 3..12) Username(clean) else null
        }
    }
}

Innerhalb von main:

println(Username.of("  Ada_L ")?.text)
println(Username.of("x")?.text)
// Username("x")   // Fehler: der Konstruktor ist privat

Ausgabe:

ada_l
null

Das Companion-Objekt gehört zur Klasse, kann also den privaten Konstruktor aufrufen, und der eigene Code der Klasse verwendet die Member des Companion-Objekts ohne Präfix. Hier erhält jedes Ticket die nächste Nummer von einem Zähler, den alle Tickets gemeinsam nutzen:

class Ticket(val holder: String) {
    val number = nextNumber++

    companion object {
        private var nextNumber = 1
        val issued: Int
            get() = nextNumber - 1
    }
}

Innerhalb von main:

val a = Ticket("Ada")
val b = Ticket("Bo")
println("${a.holder} #${a.number}, ${b.holder} #${b.number}")
println("issued: ${Ticket.issued}")

Ausgabe:

Ada #1, Bo #2
issued: 2

Kotlin hat kein static-Schlüsselwort. Die Member des Companion übernehmen diese Rolle: eine Kopie für die gesamte Klasse, erreichbar als ClassName.member. Wie jedes Objekt wird der Companion einmal erstellt, wenn die Klasse zum ersten Mal verwendet wird. Füge dort Dinge ein, die nicht von einer einzelnen Instanz abhängen, etwa Factory-Methoden und gemeinsam genutzte Zähler; alles, was die Daten einer Instanz liest, bleibt ein normales Member.

class User private constructor(val name: String) {
    fun greet() = "hi $name"             // benötigt eine Instanz: user.greet()

    companion object {
        fun guest() = User("guest")      // gehört zur Klasse: User.guest()
    }
}
challenge icon

Aufgabe

Einfach

Vervollständige die Klasse Coupon. Ihr Konstruktor ist privat, daher werden Coupons von der Factory Coupon.create(code, percent) im Companion-Objekt erstellt. Sie gibt null zurück, sofern der Code nicht aus 4 bis 10 Großbuchstaben und Ziffern besteht oder der Prozentsatz nicht zwischen 1 und 90 liegt. Das Companion-Objekt zählt außerdem die von ihm erstellten Coupons in created, das Code außerhalb des Objekts lesen, aber nicht ändern kann. apply(price) gibt den um den Rabatt verminderten Preis abgerundet zurück (price * (100 - percent) / 100).

Der bereitgestellte Code liest Zeilen SAVE10 10 200 (Code, Prozentsatz, Preis). Er gibt SAVE10: 180 oder invalid coupon SAVE10 aus und schließlich created: mit der Anzahl.

Dein Code gehört in Coupon.kt. Main.kt enthält den bereitgestellten Eingabe-/Ausgabecode und kann nicht bearbeitet werden.

Probier es selbst

fun main() {
    // Bereitgestellter Ein-/Ausgabe-Code: belasse ihn unverändert
    val input = generateSequence(::readLine).toList()
    for (line in input) {
        val (code, percent, price) = line.split(" ")
        val coupon = Coupon.create(code, percent.toInt())
        if (coupon == null) println("invalid coupon $code") else println("${coupon.code}: ${coupon.apply(price.toInt())}")
    }
    println("created: ${Coupon.created}")
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Kotlin-Playground