Saltar al contenido principal
ArceApps Logo ArceApps

Delegación en Kotlin: El poder del patrón 'by'

calendar_today
schedule ⏱️ 3 min de lectura
Delegación en Kotlin: El poder del patrón 'by'

🎭 ¿Qué es la Delegación?

En el diseño de software, la delegación es un patrón donde un objeto maneja una solicitud delegándola a un segundo objeto (el delegado). Kotlin tiene soporte de primer nivel para esto, lo que lo hace increíblemente potente y evita el boilerplate clásico de Java.

Kotlin soporta dos tipos:

  1. Delegación de Propiedades (val prop by ...)
  2. Delegación de Clases (class MyClass : Interface by ...)

⚡ Delegados de Propiedad Estándar

La librería estándar de Kotlin ya incluye joyas que deberías usar.

1. by lazy: Inicialización Perezosa

El valor se calcula solo la primera vez que se accede a él. Es thread-safe por defecto.

val heavyObject: HeavyObject by lazy {
    println("Calculando...")
    HeavyObject()
}

fun main() {
    // Aún no se ha creado nada
    println(heavyObject) // Imprime "Calculando..." y luego el objeto
    println(heavyObject) // Solo imprime el objeto (ya cacheado)
}

Uso en Android: Inicializar componentes pesados o lecturas de configuración.

2. by observable: Reaccionar a cambios

Te permite ejecutar código cada vez que una propiedad cambia su valor. Ideal para invalidar UI o logs.

var user: User by Delegates.observable(User.Empty) { property, oldValue, newValue ->
    Log.d("UserTag", "${property.name} cambió de $oldValue a $newValue")
    updateUi(newValue)
}

3. by vetoable: Validar cambios

Permite “vetar” (rechazar) el cambio de un valor si no cumple una condición.

var age: Int by Delegates.vetoable(0) { _, _, newValue ->
    newValue >= 0 // Solo acepta el cambio si es positivo
}

🏗️ Delegación de Clases: Composición sobre Herencia

Kotlin nos permite implementar una interfaz delegando la implementación real a otro objeto. Esto es la definición de libro de “Composition over Inheritance”.

interface Base {
    fun print()
}

class BaseImpl(val x: Int) : Base {
    override fun print() { print(x) }
}

class Derived(b: Base) : Base by b {
    // No necesito implementar print(), se delega automáticamente a 'b'
    // Pero PUEDO sobrescribirlo si quiero modificar el comportamiento
}

fun main() {
    val b = BaseImpl(10)
    Derived(b).print() // Imprime 10
}

Esto es brutal para patrones como Decorator o Adapter sin escribir métodos puente manuales.

🛠️ Creando tus propios Custom Delegates en Android

Lo más potente es crear tus propios delegados para encapsular lógica de Android repetitiva.

Ejemplo: Delegado para Argumentos de Fragmentos

¿Harto de leer arguments?.getString("KEY")?

class FragmentArgumentDelegate<T : Any> : ReadOnlyProperty<Fragment, T> {
    override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
        val key = property.name // Usa el nombre de la variable como clave
        return thisRef.arguments?.get(key) as T
            ?: throw IllegalStateException("Argument ${property.name} not found")
    }
}

// Extension function para usarlo bonito
fun <T : Any> argument() = FragmentArgumentDelegate<T>()

// Uso en el Fragment
class UserFragment : Fragment() {
    // Automáticamente busca en arguments con key "userId"
    private val userId: String by argument()
}

Ejemplo: SharedPreferences

Imagina guardar preferencias así:

var isDarkModeEnabled: Boolean by SharedPreferenceDelegate(context, "dark_mode", false)

// Al asignar, se guarda en disco. Al leer, se lee de disco.
isDarkModeEnabled = true

🧠 ¿Cómo funciona bajo el capó?

Cuando escribes val p by Delegate(), el compilador genera un campo oculto para el delegado y redirige los get() y set() a los métodos getValue() y setValue() del delegado. No hay magia, solo código generado inteligentemente.

🎯 Conclusión

La delegación es una de las características que hace que Kotlin sea “Conciso y Expresivo”.

  • Usa lazy para optimizar recursos.
  • Usa observable para reacciones simples de UI.
  • Usa Custom Delegates para abstraer lógica de infraestructura (Bundles, Intents, SharedPreferences) y mantener tus clases limpias.

style También te puede interesar

SOLID en Android: Clean Architecture para Apps Modernas
Android 15 de junio de 2025

SOLID en Android: Clean Architecture para Apps Modernas

Descubre cómo aplicar los principios SOLID en tu app de puzzles Android para crear una arquitectura robusta, escalable y mantenible.

Leer artículo arrow_forward
Clawdbot en Android: Compila e Instala tu Propio Nodo desde el Código Fuente
Android 7 de enero de 2026

Clawdbot en Android: Compila e Instala tu Propio Nodo desde el Código Fuente

Guía técnica para compilar la app nativa de Clawdbot para Android, permitiendo a tu asistente acceder a la cámara, ubicación y modo de voz.

Leer artículo arrow_forward
Refactoring con IA: De Legacy Code a Clean Code
IA 25 de noviembre de 2025

Refactoring con IA: De Legacy Code a Clean Code

Aprende estrategias seguras para modernizar bases de código antiguas usando asistentes de IA. Refactoriza clases masivas, elimina código muerto y migra a Kotlin.

Leer artículo arrow_forward