En este tutorial verás cómo definir e implementar interfaces en Kotlin para proveer comportamiento adicional a tus clases.
Definir Una Interfaz
Las interfaces te permiten definir tipos cuyos comportamientos pueden ser compartidos por varias clases que no están relacionadas, con el fin de crear instancias se adopten a un dominio específico.
Para definir una interfaz en Kotlin usa la palabra reservada interface
seguido del nombre de la misma. Luego entre llaves especifica el cuerpo con los miembros necesarios:
interface Interfaz {
val p1: Int // Propiedad abstracta
val p2: Boolean // Propiedad regular con accesor
get() = p1 > 0
fun m1() // Método abstracto
fun m2() { // Método regular
print("Método implementado")
}
}
Los siguientes son aspectos que debes tener en cuenta al declarar una interfaz:
- Puede contener métodos abstractos y métodos regulares con implementación
- Puede contener propiedades abstractas y regulares pero sin campos de respaldo
- No permite declaración de constructores
- Las propiedades y métodos regulares de una interfaz pueden ser sobrescritos con el modificador
override
sin tener que marcarlos conopen
a diferencia de las clases abstractas. - Una clase puede implementar múltiples interfaces
Implementar Una Interfaz
Implementa una interfaz a través del símbolo :
para separar el nombre de la clase del tipo:
class Ejemplo : Interfaz {
override val p1: Int = 0
override fun m1() {
print("Sobrescibiendo método de Interfaz")
}
}
Una vez escribas la implementación de forma Ejemplo: Interfaz
, IntelliJ IDEA te marcará en rojo la necesidad de sobrescribir los miembros abstractos.
Si presionas la bombilla podrás acceder a un menú emergente que te facilita esta tarea a través de la opción Implement members:
Esto desplegará un diálogo con la lista de miembros que puedes incluir en la sobrescritura automática:
Como resultado tendrás la sobrescritura por defecto con llamadas de la función TODO
:
class Ejemplo : Interfaz {
override val p1: Int
get() = TODO("Not yet implemented")
override fun m1() {
TODO("Not yet implemented")
}
}
Ejemplo De Interfaces En Kotlin
Usemos como referencia la declaración de una interfaz que representa a un modelo 3D como explosivo:
interface Explosive{
fun explode()
}
Todos aquellos objetos que implementen esta interfaz deberán proveer las sentencias para materializar la explosión al interior de explode()
.
Por ejemplo, si tenemos una clase para cajas llamada Box
y queremos que hagan parte del conjunto de objetos explosivos, entonces la implementamos:
class Box : Explosive {
override fun explode() = println("¡Kaboom!")
}
fun main() {
Box().explode()
}
Implementar Múltiples Interfaces
Ahora que tal si añadimos otra interfaz que permita dotar a objetos con la capacidad de incinerarse.
interface Incinerable {
fun incinerate()
}
Si queremos que las cajas aparte de ser explosivas, también sean incinerables, entonces ubicamos en la cabecera de Box
a Incinerable
con una coma y sobrescribimos a incinerate()
.
class Box : Explosive, Incinerable {
override fun explode() = println("¡Kaboom!")
override fun incinerate() = println("¡Boosh!")
}
Resolver Conflictos De Sobrescritura
Adicionalmente, supongamos que cada interfaz muestra un mensaje avisando del peligro del objeto. Podemos implementar un método llamado warning()
para ambas de la siguiente forma:
interface Explosive {
fun explode()
fun warning() = println("Explosivo")
}
interface Incinerable {
fun incinerate()
fun warning() = println("Incinerable")
}
El problema con esto, es que si una instancia de la clase Box
decidiera llamar al método warning()
habría un dilema para el compilador. Por lo que es necesario que sobrescribas el método para acotar su comportamiento:
class Box : Explosive, Incinerable {
override fun explode() = println("¡Kaboom!")
override fun incinerate() = println("¡Boosh!")
override fun warning() {
super<Incinerable>.warning()
super<Explosive>.warning()
}
}
Al sobrescribir a warning()
puedes eliminar el conflicto de compilación. Luego puedes proceder a la llamada de la implementación que desees, a través de la referencia super
junto al tipo base con paréntesis angulares: super<Tipo>
.
fun main() {
val box = Box()
box.warning()
box.explode()
box.incinerate()
}
Salida:
Incinerable
Explosivo
¡Kaboom!
¡Boosh!