Clases abstractas
Parte de la sección Programación orientada a objetos del Journey de Kotlin de Coddy. Lección 20 de 57.
Una clase abstract es una superclase que no puede instanciarse por sí sola. Puede declarar miembros abstract sin un cuerpo, y toda subclase concreta debe implementarlos:
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
}Dentro de main:
val shapes: List<Shape> = listOf(Circle(1.0), Rect(2.0, 3.0))
for (s in shapes) println(s.describe())Salida:
circle with area 3.14
rect with area 6.0Una clase abstracta es open sin la palabra clave, y sus miembros abstractos también son open, por lo que las subclases solo escriben override. Crear la propia clase abstracta no compila, y una subclase que omita un miembro abstracto también debe ser abstracta. Usa una clase abstracta cuando la superclase no tenga un comportamiento propio sensato para algunos miembros:
// val s = Shape("blob") // error: no se puede crear una instancia de una clase abstracta
// class Blob : Shape("blob") // error: Blob no implementa area()
abstract class Polygon(name: String) : Shape(name) // bien: sigue siendo abstractaUna clase abstracta puede tener un constructor, estado y métodos normales, que las subclases heredan. Un uso común es un procedimiento fijo cuyos pasos varían, el método plantilla: el método de la superclase ejecuta los pasos y las subclases completan los abstractos:
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"
}Dentro de main:
println(Sales(420).render())
println(Stock(17).render())Salida:
== Sales ==
total: 420
(end)
== Stock ==
items: 17
(counted today)Las propiedades abstractas funcionan de la misma manera. La subclase proporciona el valor como una propiedad del constructor, una propiedad almacenada o un 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 de main:
val staff = listOf(Salaried("Ada", 4000), Hourly("Bo", 80, 25))
for (w in staff) println("${w.name}: ${w.yearly()}")Salida:
Ada: 48000
Bo: 24000Desafío
FácilDiscount es una clase abstracta. Declara el método abstracto amount(price) e implementa apply(price), que devuelve el precio menos amount(price), pero nunca un valor inferior a 0. Completa las subclases: PercentOff(percent) toma ese porcentaje del precio (redondeado hacia abajo), FixedOff(value) toma un valor fijo y SpendMore(threshold, off) toma off solo cuando el precio es al menos threshold.
El código proporcionado lee el precio y después aplica descuentos de p,10, f,300 o s,500,50, aplica cada uno al precio e imprime 1000 -> 900.
Tu código debe ir en Discount.kt, PercentOff.kt, FixedOff.kt y SpendMore.kt. Main.kt contiene el código proporcionado de entrada/salida y no se puede editar.
Pruébalo tú mismo
fun main() {
// Código de entrada/salida suministrado: déjalo tal como está
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)}")
}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación orientada a objetos
1Clases y objetos
Trabajar con archivosDefinir clasesConstructores primariosBloques init y validaciónConstructores secundariosRepaso - Tarjeta de biblioteca4Herencia
Clases abiertas y subclasesSobrescritura de miembrossuper y constructoresClases abstractasRepaso: directorio del personal2Propiedades y encapsulación
Accesores personalizadosModificadores de visibilidadSetters privadoslazy y lateinitRepaso: cuenta bancaria5Interfaces
Declaración de interfacesMétodos predeterminadosInterfaces múltiplesInterfaces como tiposRepaso: métodos de pago8Genéricos
Funciones genéricasClases genéricasRestricciones de tiposVariancia con in y outRepaso - Cola de prioridad11Proyecto: Gestión de biblioteca
Libros y miembrosPréstamo de librosPractica por tu cuenta: Playground de Kotlin