En Kotlin, clases abstractas (abstract class) e interfaces (interface) se utilizan para declarar lógica abstracta, pero hay diferencias significativas entre ellas:
abstract class Animal(val name: String) { abstract fun makeSound() fun info() = println("I am $name") } interface Movable { fun move() } class Cat(name: String) : Animal(name), Movable { override fun makeSound() = println("Meow") override fun move() = println("Cat moves") }
¿Puede una interfaz en Kotlin contener estado (backing field)?
La mayoría responde que se pueden declarar propiedades en una interfaz, pero aún no tienen backing field: solo getters/setters sin almacenamiento de valor. Incluso si se escribe get() = ... — el valor se calculará cada vez.
Ejemplo:
interface MyInterface { val value: Int get() = 42 // no hay almacenamiento de valor, cálculo en el vuelo }
Historia
En un gran proyecto, un desarrollador senior intentó almacenar estado en una interfaz (por ejemplo, un contador), esperando que la propiedad var count: Int tuviera backing field. Como resultado, todas las clases que implementaban la interfaz tuvieron que implementar el almacenamiento de valor de diferentes maneras, lo que resultó en una lógica inestable (los datos se perdían si se olvidaba sobreescribir el setter).
Historia
Uno de los desarrolladores usó una clase abstracta donde se necesitaba múltiples implementaciones de diferentes estrategias de comportamiento (patrón estrategia). Como resultado, surgió un problema: solo una clase base en la jerarquía, pero se requería composición para diferentes aspectos de comportamiento. Hubo que cambiar la arquitectura a interfaces.
Historia
El equipo intentó heredar dos clases abstractas a la vez (una con lógica, otra con utilidades comunes), lo que no es posible en Kotlin. El problema se identificó ya en la fase de expansión de la aplicación. Esto resultó en una deuda técnica significativa, ya que las clases tuvieron que reorganizarse rápidamente.