En Kotlin, la delegación de comportamientos se implementa mediante la palabra clave by directamente en la firma de la clase. Esto permite enviar automáticamente las llamadas a los métodos de la interfaz (o de varias interfaces) a otro objeto con una implementación, reduciendo el boilerplate y facilitando la composición.
La aparición de la delegación de interfaces es un intento de eliminar las limitaciones y desventajas de la herencia múltiple. Es la idea de "composición sobre herencia": delegamos comportamientos sin recurrir a la jerarquía de clases. Tomado de lenguajes donde la composición es más popular (por ejemplo, Go, Scala).
En Java y otros lenguajes, a menudo es necesario crear una interfaz y realizar manualmente cada método, transfiriendo la lógica a otro campo (patrón Adapter de Objeto), lo cual rápidamente se vuelve obsoleto a medida que crece el número de métodos.
Kotlin permite delegar declarativamente una interfaz usando by:
interface Logger { fun log(msg: String) } class ConsoleLogger: Logger { override fun log(msg: String) = println(msg) } class Service(logger: Logger): Logger by logger { fun doWork() { log("Trabajo iniciado") // ... } } val service = Service(ConsoleLogger()) service.doWork()
Características clave:
¿Qué sucede si se agrega un método propio de la interfaz en la clase Service con la misma firma?
La implementación propia "anula" la delegada: es decir, prevalece el método definido explícitamente en la clase:
class Service(logger: Logger): Logger by logger { override fun log(msg: String) = println("PREFIX: $msg") }
¿Puede una clase delegar múltiples interfaces a diferentes objetos?
Sí, una clase puede implementar y delegar múltiples interfaces a diferentes objetos, pero cada interfaz se delega a un solo objeto:
class Service( logger: Logger, tracker: Tracker ): Logger by logger, Tracker by tracker
¿En qué se diferencia la delegación de interfaz de la delegación de propiedades mediante by?
La clase implementa manualmente la interfaz, cada método llama al delegado, al agregar nuevos métodos se olvida actualizar la proxy, lo que lleva a errores.
Ventajas:
Desventajas:
Se utiliza la delegación del lenguaje, solo los métodos no estándar se implementan dentro de la clase, nueva funcionalidad se añade sin grandes cambios.
Ventajas:
Desventajas: