Abstrakte Klassen
Teil des Abschnitts Objektorientierte Programmierung der Kotlin-Journey von Coddy. Lektion 20 von 57.
Eine abstract-Klasse ist eine Oberklasse, die nicht eigenständig instanziiert werden kann. Sie kann abstract-Member ohne Rumpf deklarieren, und jede konkrete Unterklasse muss sie implementieren:
abstract class Shape(val name: String) {
abstract fun area(): Double
fun describe() = "$name with area ${area()}"
}
class Circle(val r: Double) : Shape("circle") {
override fun area() = 3.14 * r * r
}
class Rect(val w: Double, val h: Double) : Shape("rect") {
override fun area() = w * h
}Innerhalb von main:
val shapes: List<Shape> = listOf(Circle(1.0), Rect(2.0, 3.0))
for (s in shapes) println(s.describe())Ausgabe:
circle with area 3.14
rect with area 6.0Eine abstrakte Klasse ist ohne das Schlüsselwort open, und auch ihre abstrakten Member sind open, sodass Unterklassen nur override schreiben. Das Erstellen der abstrakten Klasse selbst lässt sich nicht kompilieren, und eine Unterklasse, die ein abstraktes Member auslässt, muss ebenfalls abstrakt sein. Verwende eine abstrakte Klasse, wenn die Oberklasse für einige Member kein sinnvolles eigenes Verhalten hat:
// val s = Shape("blob") // Fehler: kann keine Instanz einer abstrakten Klasse erstellen
// class Blob : Shape("blob") // Fehler: Blob implementiert area() nicht
abstract class Polygon(name: String) : Shape(name) // in Ordnung: immer noch abstraktEine abstrakte Klasse kann einen Konstruktor, einen Zustand und normale Methoden haben, die Unterklassen erben. Eine häufige Verwendung ist ein festgelegter Ablauf, dessen Schritte variieren, die Template-Methode: Die Methode der Oberklasse führt die Schritte aus, und die Unterklassen füllen die abstrakten Schritte aus:
abstract class Report(val title: String) {
fun render() = "== $title ==\n${body()}\n(${footer()})"
abstract fun body(): String
open fun footer() = "end"
}
class Sales(val total: Int) : Report("Sales") {
override fun body() = "total: $total"
}
class Stock(val items: Int) : Report("Stock") {
override fun body() = "items: $items"
override fun footer() = "counted today"
}Innerhalb von main:
println(Sales(420).render())
println(Stock(17).render())Ausgabe:
== Sales ==
total: 420
(end)
== Stock ==
items: 17
(counted today)Abstrakte Eigenschaften funktionieren auf dieselbe Weise. Die Unterklasse stellt den Wert als Konstruktor-Eigenschaft, gespeicherte Eigenschaft oder Getter bereit:
abstract class Worker(val name: String) {
abstract val monthly: Int
fun yearly() = monthly * 12
}
class Salaried(name: String, override val monthly: Int) : Worker(name)
class Hourly(name: String, val hours: Int, val rate: Int) : Worker(name) {
override val monthly: Int
get() = hours * rate
}Innerhalb von main:
val staff = listOf(Salaried("Ada", 4000), Hourly("Bo", 80, 25))
for (w in staff) println("${w.name}: ${w.yearly()}")Ausgabe:
Ada: 48000
Bo: 24000Aufgabe
EinfachDiscount ist eine abstrakte Klasse. Sie deklariert die abstrakte Methode amount(price) und implementiert apply(price), die den Preis minus amount(price) zurückgibt, jedoch niemals weniger als 0. Vervollständige die Unterklassen: PercentOff(percent) nimmt diesen Prozentsatz des Preises (abgerundet), FixedOff(value) nimmt einen festen Wert, und SpendMore(threshold, off) nimmt off nur dann, wenn der Preis mindestens threshold beträgt.
Der bereitgestellte Code liest den Preis ein und wendet anschließend p,10, f,300 oder s,500,50 als Rabatt an, wendet jeden davon auf den Preis an und gibt 1000 -> 900 aus.
Dein Code gehört in Discount.kt, PercentOff.kt, FixedOff.kt und SpendMore.kt. Main.kt enthält den bereitgestellten Eingabe-/Ausgabecode und kann nicht bearbeitet werden.
Probier es selbst
fun main() {
// Bereitgestellter Ein-/Ausgabecode: belasse ihn wie er ist
val input = generateSequence(::readLine).toList()
val price = input[0].toInt()
for (line in input.drop(1)) {
val p = line.split(",")
val discount: Discount = when (p[0]) {
"p" -> PercentOff(p[1].toInt())
"f" -> FixedOff(p[1].toInt())
else -> SpendMore(p[1].toInt(), p[2].toInt())
}
println("$price -> ${discount.apply(price)}")
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Klassen und Objekte
Arbeiten mit DateienKlassen definierenPrimärkonstruktoreninit-Blöcke und ValidierungSekundärkonstruktorenRückblick – Bibliotheksausweis4Vererbung
Offene Klassen und UnterklassenÜberschreiben von Membernsuper und KonstruktorenAbstrakte KlassenRückblick – Mitarbeiterverzeichnis2Eigenschaften und Kapselung
Benutzerdefinierte ZugriffsmethodenSichtbarkeitsmodifikatorenPrivate Setterlazy und lateinitWiederholung – Bankkonto5Schnittstellen
Schnittstellen deklarierenStandardmethodenMehrere SchnittstellenSchnittstellen als TypenRückblick – Zahlungsmethoden8Generics
Generische FunktionenGenerische KlassenTypbeschränkungenVarianz mit in und outRückblick – Prioritätswarteschlange11Projekt: Bibliotheksverwaltung
Bücher und MitgliederBücher ausleihenÜbe selbstständig: Kotlin-Playground