Herencia
Explicación de la implementación de la herencia.
Para explicar este concepto vamos a extender un poco la clase Slime antes de empezar:
val BAD_WORDS: Array<String> = arrayOf("Feo", "Tonto", "CuatroOjos")
open class Slime (name: String = "slimePorDefecto", hp: Int = 100, ap: Int = 5){
private val name: String
private var hp: Int
private var ap: Int
private var alive: Boolean = true
init {
if (name in BAD_WORDS) this.name = "BuenIntento" else this.name = name
if (hp <= 100) this.hp = hp else this.hp = Random.nextInt(0, 100)
if (ap <= 5) this.ap = ap else this.ap = Random.nextInt(0, 5)
}
fun getName(): String = this.name
fun getHp(): Int = this.hp
fun getAp(): Int = this.ap
fun getAlive(): Boolean = this.alive
fun setHp(value: Int) {
if (value > 100) this.hp = Random.nextInt(0, 100) else this.hp = value
}
fun setAp(value: Int) {
if (value > 5) this.ap = Random.nextInt(0, 5) else this.ap = value
}
fun sayHello() = println("¡Hola soy ${getName()}")
fun heal() {
this.hp = 100
}
fun attack() = println("¡¡Al Ataque!!")
fun evolve() {
this.ap *= 2
}
fun die() {
this.alive = false
}
}
El problema que tenemos que solucionar actualmente es que tenemos Slimes de varios colores. Cada color de Slime tiene su propio tipo y por tanto sus ataques serán diferentes así como sus métodos.
Por ejemplo, el slime azul será de tipo agua y podrá mantener la respiración bajo el agua más que el resto. El rojo, de tipo fuego, tendrá resistencia a altas temperaturas. Sin embargo, todos ellos comparten todas las propiedades de la clase Slime.
La clase Slime
en este caso se convertirá en la clase Padre o Superclase de las clases específicas de SlimeAgua
o SlimeFuego
.
Las clases específicas SlimeAgua
y SlimeFuego
compartirán las propiedades de la clase padre Slime
y además podrán tener las suyas particulares. Esto es lo que conocemos como Herencia.
La clase Any
La clase Any es la raíz de la jerarquía de clases en Kotlin. Esto significa que cualquier clase que no herede explícitamente de otra superclase, lo hará implícitamente de la clase Any.
Esta clase Any tiene tres métodos según su implementación en Any.kt:
equals()
: Indica si otro objeto es igual al actual.hashCode()
: Retorna el código hash asociado al objeto.toString()
: Retorna la representación enString
del objeto.
Sintaxis
La sintaxis para aplicar la herencia es muy sencilla en Kotlin:
open class Padre
class Descendiente: Padre()
Modificador open
Las clases por defecto tienen el modificador final
, lo que significa que son el útimo eslabón de su arbol genealógico. Para que se pueda heredar de la clase Padre, hay que añadir a su cabecera el modificador open
.
Constructor primario
En el caso de que haya un constructor primario en la clase padre, habrá que inicializarlo en la clase descendiente:
open class Padre(val Arg1: T, val Arg2: T)
class Descendiente(Arg1: T, Arg2: T, val Arg3: T): Padre(Arg1, Arg2)
Constructor secundario
Si la clase padre no tiene constructor primario o deseas realizar la llamada del mismo, desde un constructor secundario de la subclase, entonces usa la palabra reservada constructor
junto a la palabra reservada super
para la llamada.
open class Padre(val Arg1: T, val Arg2: T)
class Descendiente: Padre {
constructor(Arg1: T, Arg2: T, val Arg3: T) : super(Arg1, Arg2)
}
Aplicación práctica
La sintaxis de aplicación de la herencia es la siguiente:
class SlimeAgua(name: String, hp: Int, ap: Int, lungs: Int): Slime(name, hp, ap) {
private var waterResistance: Int
private var timeUnderWater: Int = 0
init{
this.waterResistance = lungs * 120
}
fun getWaterResistance(): Int = this.waterResistance
fun getTimeUnderWater(): Int = this.timeUnderWater
fun breathe() {
this.timeUnderWater = 0
}
fun immerse() {
this.waterResistance++
}
}
Como puede ver, los argumentos que se le pasan a la clase SlimeAgua
pero pertenecen a la clase Slime
, no se inicializan con val o var.
lungs
tampoco se inicializa con val o var por que no es un atributo, sino que se utiliza para inicializar el atributo waterResistance
.
La clase SlimeAgua
luego llama al constructor de la clase Slime
de la que hereda para que se cree una instancia de la misma y poder crearse a partir de esa una instancia de la clase SlimeAgua
.
Después nos encontramos con las propiedades que son exclusivas de la clase SlimeAgua
. Tanto atributos como métodos pueden ser específicos.
Ahora si que podemos hacer un objeto azulito como dios manda:
val azulito: SlimeAgua = SlimeAgua("CuatroOjos", 1000000, 500, 2)
println("name: " + azulito.getName())
println("hp: " + azulito.getHp())
println("ap: " + azulito.getAp())
println("alive: " + azulito.getAlive())
println("water Resistance: " + azulito.getWaterResistance())
println("time under Water: " + azulito.getTimeUnderWater())
azulito.sayHello()
azulito.heal()
println("hp: " + azulito.getHp())
azulito.attack()
repeat(10) {
azulito.immerse()
}
println("time under Water: " + azulito.getTimeUnderWater())
println("\n${azulito.getName()} ha muerto.")
azulito.die()
println(println("alive: " + azulito.getAlive()))
/*
name: BuenIntento
hp: 25
ap: 2
alive: true
water Resistance: 240
time under Water: 0
¡Hola soy BuenIntento
hp: 100
¡¡Al Ataque!!
time under Water: 10
BuenIntento ha muerto.
alive: false */
Se ve en el ejemplo anterior que azulito tiene acceso a todos los miembros de Slime
así como a las propiedades específicas de SlimeAgua
.
Last updated