Sobes.tech
Middle

Môžeš vysvetliť princíp fungovania delegáta v triede v Kotlin?

sobes.tech AI

Odpoveď od AI

Delegát v Kotlin je objekt, ktorý preberá vykonávanie určitej úlohy alebo deleguje volania metód na iný objekt.

Hlavné scenáre použitia:

  1. Delegovanie vlastností (Delegated Properties): Prenos riadenia getterov a setterov vlastnosti na iný objekt.

    • lazy: Výpočet hodnoty vlastnosti pri prvom prístupe.
    • observable: Vykonanie akcie pri zmene hodnoty vlastnosti.
    • vetoable: Zákaz zmeny hodnoty vlastnosti na základe podmienky.
    class Example {
        // Vypočíta sa iba pri prvom prístupe
        val lazyValue: String by lazy {
            println("Vypočítavam!")
            "Ahoj"
        }
    
        // Volá sa pri každej zmene hodnoty
        var name: String by Delegates.observable("<žiadne meno>") { prop, old, new ->
            println("Meno sa zmenilo z $old na $new")
        }
    }
    
  2. Delegovanie rozhraní (Class Delegation): Implementácia rozhrania prostredníctvom presmerovania volaní metód na iný objekt.

    interface Base {
        fun print()
    }
    
    class BaseImpl(val x: Int) : Base {
        override fun print() {
            println(x)
        }
    }
    
    // Implementuje Base, delegujúc volania na BaseImpl
    class Derived(b: Base) : Base by b
    
    fun main() {
        val b = BaseImpl(10)
        Derived(b).print() // Vypíše 10
    }
    
  3. Delegovanie funkcií (Function Delegation): Hoci neexistuje explicitná syntax pre delegovanie jednotlivých funkcií, ako pre vlastnosti alebo rozhrania, je to konceptuálne realizované cez kompozíciu a volanie metód iného objektu.

Ako funguje delegovanie vlastností:

Kotlin kompilátor generuje pomocný kód. Pre vlastnosť delegovanú objektom delegate generuje kompilátor skryté vlastnosti a volá metódy getValue a setValue (pre meniteľné vlastnosti) na objekte delegate, odovzdávajúc potrebný kontext (inštanciu triedy, metadáta vlastnosti).

// Príklad pseudokódu, ako kompilátor spracováva: val p: String by delegate
/*
private val _p: Delegate<Any?, String> = delegate_initializer
val p: String
    get() = _p.getValue(this, ::p) // Volanie getValue na delegáte
*/

Delegujúci objekt musí mať zodpovedajúce metódy:

  • getValue(thisRef, property: KProperty<*>): T pre vlastnosť typu T. thisRef je inštancia triedy, property metadáta vlastnosti.
  • setValue(thisRef, property: KProperty<*>, value: T) pre meniteľnú vlastnosť.

Výhody používania delegátov:

  • Opakovane použiteľný kód: Všeobecná logika (lenivá inicializácia, sledovanie zmien) sa prenáša do samostatného delegáta a je opakovane použitelná.
  • Zlepšenie čitateľnosti: Kód je menej objemný, boilerplate kód je skrytý vo vnútri delegáta.
  • Modularita: Logika správy vlastností alebo implementácie rozhraní je oddelená od hlavnej logiky triedy.