Menu
Coddy logo textTech

Classes Abstratas

Parte da seção Programação Orientada a Objetos do Journey de Kotlin da Coddy. Lição 20 de 57.

Uma classe abstract é uma superclasse que não pode ser instanciada por conta própria. Ela pode declarar membros abstract sem um corpo, e toda subclasse concreta deve implementá-los:

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())

Saída:

circle with area 3.14
rect with area 6.0

Uma classe abstrata é open sem a palavra-chave, e seus membros abstratos também são open, portanto as subclasses escrevem apenas override. Criar a própria classe abstrata não compila, e uma subclasse que omite um membro abstrato também deve ser abstrata. Use uma classe abstrata quando a superclasse não tiver um comportamento próprio sensato para alguns membros:

// val s = Shape("blob")                       // erro: não é possível criar uma instância de uma classe abstrata
// class Blob : Shape("blob")                  // erro: Blob não implementa area()
abstract class Polygon(name: String) : Shape(name)   // ok: ainda abstrato

Uma classe abstrata pode ter um construtor, estado e métodos normais, que as subclasses herdam. Um uso comum é um procedimento fixo cujas etapas variam, o método template: o método da superclasse executa as etapas, e as subclasses preenchem as abstratas:

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())

Saída:

== Sales ==
total: 420
(end)
== Stock ==
items: 17
(counted today)

As propriedades abstratas funcionam da mesma maneira. A subclasse fornece o valor como uma propriedade do construtor, uma propriedade armazenada ou um 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()}")

Saída:

Ada: 48000
Bo: 24000
challenge icon

Desafio

Fácil

Discount é uma classe abstrata. Ela declara o método abstrato amount(price) e implementa apply(price), que retorna o preço menos amount(price), mas nunca abaixo de 0. Complete as subclasses: PercentOff(percent) aplica essa porcentagem ao preço (arredondada para baixo), FixedOff(value) aplica um valor fixo, e SpendMore(threshold, off) aplica off somente quando o preço é pelo menos threshold.

O código fornecido lê o preço e, em seguida, aplica os descontos p,10, f,300 ou s,500,50, aplica cada um ao preço e imprime 1000 -> 900.

Seu código deve ser colocado em Discount.kt, PercentOff.kt, FixedOff.kt e SpendMore.kt. Main.kt contém o código fornecido de entrada/saída e não pode ser editado.

Experimente você mesmo

fun main() {
    // Código de entrada/saída fornecido: mantenha-o 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)}")
    }
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Playground de Kotlin