Clases Abstractas En Kotlin

En este tutorial aprenderás acerca de la declaración de clases abstractas en Kotlin para definir tipos que permitan múltiples implementaciones.

El Modificador abstract

Una clase abstracta es aquella que está marcada con el modificador abstract en su declaración. Esto evita que se creen instancias de la clase, pero no impide que se creen subclases a partir de ella.

abstract class ClaseAbstracta{
    // Propiedades regulares
    // Propiedades abstractas
    // Métodos abstractos
    // Métodos regulares
}

Los miembros de una clase abstracta también pueden ser marcados como abstract, lo que significa que no tendrán implementación, debido a que esta será exigida para las subclases.

abstract class ClaseAbstracta {
    abstract val propiedadAbstracta: Int

    abstract fun metodoAbstracto()

    fun metodoNoAbstracto() {
        // Cuerpo
    }
}

Las clases que deriven de una clase abstracta deben sobrescribir a los miembros abstractos con el modificador override:

class Subclase : ClaseAbstracta() {
    override val propiedadAbstracta: Int = 10

    override fun metodoAbstracto() {
        print(propiedadAbstracta)
    }
}

Como ves, una clase abstracta no debe ser marcada con open para permitir herencia al igual que sus miembros abstractos.

Úsalo solo con los miembros no abstractos si deseas sobrescribirlos.

Ejemplo De Clases Abtractas En Kotlin

Tomemos como ejemplo el diseño para poder ejecutar ataques físicos de un personaje en un videojuego. Estos serán: golpe doble, cabezazo y bola de fuego.

Por simplicidad, al ejecutarse cada uno imprimiremos el mensaje de ejecución junto al daño realizado.

Tendremos la clase Attack la cual depende de una propiedad de daño base y posee un método que ejecuta hipotéticamente el efecto.

abstract class Attack {
    val baseDamage: Int = 10

    abstract fun execute(): String
}

No deseamos que se creen instancias de Attack, ya que esta clase solo representa el concepto de ataque, más no los comportamientos específicos que deseamos aplicar.

Lo que deseamos es que execute() sea implementado por las subclases propuestas al inicio de la siguiente forma:

class Headbutt : Attack() {
    override fun execute(): String {
        return "¡Cabezazo! ${baseDamage + 1}"
    }
}

class DoubleKick : Attack() {
    override fun execute(): String {
        return "¡Golpe doble! ${baseDamage + 2}"
    }
}

class Fireball : Attack() {
    override fun execute(): String {
        return "¡Bola de fuego! ${baseDamage + 3}"
    }
}

Cada clase derivada tiene sus propias sentencias a la hora de ejecutarse. El retorno será un String con el mensaje del ataque junto al daño realizado.

Con este diseño generado, crea una lista con una instancia de cada ataque y ejecútalos secuencialmente:

fun main() {
    val attacks = mutableListOf(Headbutt(), DoubleKick(), Fireball())
    attacks.forEach { println(it.execute()) }
}

Salida:

¡Cabezazo! 11
¡Golpe doble! 12
¡Bola de fuego! 13

Obviamente si intentas añadir una instancia de Attack a la lista verás el siguiente error en IntelliJ IDEA:

Cannot create an instance of an abstract class
Clases abstractas en Kotlin: Cannot create an instance of an abstract class

¿Ha sido útil esta publicación?