Classi astratte
Fa parte della sezione Programmazione orientata agli oggetti del percorso Kotlin di Coddy. Lezione 20 di 57.
Una classe abstract è una superclasse che non può essere istanziata autonomamente. Può dichiarare membri abstract senza corpo e ogni sottoclasse concreta deve implementarli:
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
}All'interno di main:
val shapes: List<Shape> = listOf(Circle(1.0), Rect(2.0, 3.0))
for (s in shapes) println(s.describe())Output:
circle with area 3.14
rect with area 6.0Una classe astratta è aperta senza la parola chiave, e anche i suoi membri astratti sono aperti, quindi le sottoclassi scrivono solo override. Creare la classe astratta stessa non compila, e anche una sottoclasse che omette un membro astratto deve essere astratta. Usa una classe astratta quando la superclasse non ha un comportamento sensato per alcuni membri:
// val s = Shape("blob") // errore: non è possibile creare un'istanza di una classe astratta
// class Blob : Shape("blob") // errore: Blob non implementa area()
abstract class Polygon(name: String) : Shape(name) // corretto: ancora astrattaUna classe astratta può avere un costruttore, uno stato e metodi normali, che le sottoclassi ereditano. Un uso comune è una procedura fissa i cui passaggi variano, il metodo template: il metodo della superclasse esegue i passaggi e le sottoclassi completano quelli astratti:
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"
}All'interno di main:
println(Sales(420).render())
println(Stock(17).render())Output:
== Sales ==
total: 420
(end)
== Stock ==
items: 17
(counted today)Le proprietà astratte funzionano allo stesso modo. La sottoclasse fornisce il valore come proprietà del costruttore, proprietà memorizzata o 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
}Dentro main:
val staff = listOf(Salaried("Ada", 4000), Hourly("Bo", 80, 25))
for (w in staff) println("${w.name}: ${w.yearly()}")Output:
Ada: 48000
Bo: 24000Sfida
FacileDiscount è una classe astratta. Dichiara il metodo astratto amount(price) e implementa apply(price), che restituisce il prezzo meno amount(price), ma mai un valore inferiore a 0. Completa le sottoclassi: PercentOff(percent) sottrae quella percentuale dal prezzo (arrotondata per difetto), FixedOff(value) sottrae un valore fisso e SpendMore(threshold, off) sottrae off solo quando il prezzo è almeno threshold.
Il codice fornito legge il prezzo e poi applica gli sconti p,10, f,300 o s,500,50 al prezzo e stampa 1000 -> 900.
Il tuo codice va inserito in Discount.kt, PercentOff.kt, FixedOff.kt e SpendMore.kt. Main.kt contiene il codice di input/output fornito e non può essere modificato.
Provalo tu
fun main() {
// Supplied input/output code: keep it as it is
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)}")
}
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Classi e oggetti
Lavorare con i fileDefinire le classiCostruttori primariBlocchi init e convalidaCostruttori secondariRiepilogo - Tessera della biblioteca4Ereditarietà
Classi aperte e sottoclassiRidefinizione dei membrisuper e costruttoriClassi astratteRiepilogo - Elenco del personale2Proprietà e incapsulamento
Accessor personalizzatiModificatori di visibilitàSetter privatilazy e lateinitRipasso - Conto bancario5Interfacce
Dichiarare le interfacceMetodi predefinitiInterfacce multipleLe interfacce come tipiRiepilogo - Metodi di pagamento8Tipi generici
Funzioni genericheClassi genericheVincoli sui tipiVarianza con in e outRiepilogo - Coda con priorità11Progetto: Gestione della biblioteca
Libri e sociPrendere in prestito i libriEsercitati da solo: Playground Kotlin