Klasy abstrakcyjne
Część sekcji Programowanie obiektowe ścieżki Kotlin w Coddy. Lekcja 20 z 57.
Klasa abstract jest nadklasą, której nie można samodzielnie utworzyć jako instancji. Może deklarować składowe abstract bez treści, a każda konkretna podklasa musi je zaimplementować:
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
}Wewnątrz main:
val shapes: List<Shape> = listOf(Circle(1.0), Rect(2.0, 3.0))
for (s in shapes) println(s.describe())Wynik:
circle with area 3.14
rect with area 6.0Klasa abstrakcyjna jest otwarta bez słowa kluczowego, a jej abstrakcyjne składowe również są otwarte, więc podklasy zapisują tylko override. Utworzenie samej klasy abstrakcyjnej nie kompiluje się, a podklasa, która pomija abstrakcyjną składową, również musi być abstrakcyjna. Użyj klasy abstrakcyjnej, gdy nadklasa nie ma sensownego własnego zachowania dla niektórych składowych:
// val s = Shape("blob") // błąd: nie można utworzyć instancji klasy abstrakcyjnej
// class Blob : Shape("blob") // błąd: Blob nie implementuje area()
abstract class Polygon(name: String) : Shape(name) // poprawne: nadal abstrakcyjnaKlasa abstrakcyjna może mieć konstruktor, stan i zwykłe metody, które dziedziczą podklasy. Częstym zastosowaniem jest stała procedura, której kroki się różnią — metoda szablonowa: metoda nadklasy wykonuje kroki, a podklasy uzupełniają abstrakcyjne:
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"
}Wewnątrz main:
println(Sales(420).render())
println(Stock(17).render())Wynik:
== Sales ==
total: 420
(end)
== Stock ==
items: 17
(counted today)Właściwości abstrakcyjne działają tak samo. Podklasa dostarcza wartość jako właściwość konstruktora, przechowywaną właściwość lub getter:
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
}Wewnątrz main:
val staff = listOf(Salaried("Ada", 4000), Hourly("Bo", 80, 25))
for (w in staff) println("${w.name}: ${w.yearly()}")Wynik:
Ada: 48000
Bo: 24000Wyzwanie
ŁatwyDiscount jest klasą abstrakcyjną. Deklaruje abstrakcyjną metodę amount(price) i implementuje apply(price), która zwraca cenę pomniejszoną o amount(price), ale nigdy mniej niż 0. Uzupełnij podklasy: PercentOff(percent) odejmuje podany procent ceny (zaokrąglony w dół), FixedOff(value) odejmuje stałą wartość, a SpendMore(threshold, off) odejmuje off tylko wtedy, gdy cena wynosi co najmniej threshold.
Dostarczony kod odczytuje cenę, a następnie rabaty p,10, f,300 lub s,500,50, stosuje każdy z nich do ceny i wypisuje 1000 -> 900.
Twój kod umieść w plikach Discount.kt, PercentOff.kt, FixedOff.kt i SpendMore.kt. Main.kt zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.
Spróbuj swoich sił
fun main() {
// Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
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)}")
}
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Klasy i obiekty
Praca z plikamiDefiniowanie klasKonstruktory główneBloki init i walidacjaKonstruktory dodatkowePodsumowanie — karta biblioteczna4Dziedziczenie
Klasy otwarte i podklasyNadpisywanie składowychsuper i konstruktoryKlasy abstrakcyjnePodsumowanie – katalog pracowników7Klasy specjalne
Klasy danychKlasy wyliczenioweHierarchie zapieczętowaneequals, hashCode, toStringPodsumowanie — śledzenie zamówień10Wzorce projektowe, część 2
Delegowanie za pomocą byWzorzec dekoratoraWzorzec budowniczegoWzorzec stanu2Właściwości i hermetyzacja
Własne akcesoryModyfikatory widocznościPrywatne setterylazy i lateinitPowtórka – konto bankowe5Interfejsy
Deklarowanie interfejsówMetody domyślneWiele interfejsówInterfejsy jako typyPowtórzenie – metody płatności8Typy generyczne
Funkcje generyczneKlasy generyczneOgraniczenia typówKowariancja i kontrawariancja: in i outPodsumowanie — kolejka priorytetowa11Projekt: Zarządzanie biblioteką
Książki i czytelnicyWypożyczanie książekPoćwicz samodzielnie: Edytor online Kotlin