Sobes.tech
Middle

Můžeš vysvětlit princip fungování delegáta ve třídě v Kotlinu?

sobes.tech AI

Odpověď od AI

Delegát v Kotlinu je objekt, který přebírá vykonávání určitého úkolu nebo deleguje volání metod jinému objektu.

Hlavní scénáře použití:

  1. Delegování vlastností (Delegated Properties): Předání řízení getterům a setterům vlastnosti jinému objektu.

    • lazy: Výpočet hodnoty vlastnosti při prvním přístupu.
    • observable: Provádění akce při změně hodnoty vlastnosti.
    • vetoable: Zákaz změny hodnoty vlastnosti na základě podmínky.
    class Example {
        // Vypočítá se pouze při prvním přístupu
        val lazyValue: String by lazy {
            println("Vypočítávám!")
            "Ahoj"
        }
    
        // Volá se při každé změně hodnoty
        var name: String by Delegates.observable("<žádné jméno>") { prop, old, new ->
            println("Jméno se změnilo z $old na $new")
        }
    }
    
  2. Delegování rozhraní (Class Delegation): Implementace rozhraní přesměrováním volání metod na jiný objekt.

    interface Base {
        fun print()
    }
    
    class BaseImpl(val x: Int) : Base {
        override fun print() {
            println(x)
        }
    }
    
    // Implementuje Base, deleguje volání na BaseImpl
    class Derived(b: Base) : Base by b
    
    fun main() {
        val b = BaseImpl(10)
        Derived(b).print() // Vytiskne 10
    }
    
  3. Delegování funkcí (Function Delegation): Ačkoliv neexistuje explicitní syntaxe pro delegování jednotlivých funkcí, jako u vlastností nebo rozhraní, je to konceptuálně realizováno přes kompozici a volání metod jiného objektu.

Jak funguje delegování vlastností:

Kotlin kompilátor generuje pomocný kód. Pro vlastnost delegovanou objektem delegate generuje kompilátor skrytou vlastnost a volá metody getValue a setValue (pro měnitelné vlastnosti) na objektu delegate, předávající potřebný kontext (instance třídy, metadata vlastnosti).

// Příklad pseudokódu, jak kompilátor zpracovává: val p: String by delegate
/*
private val _p: Delegate<Any?, String> = delegate_initializer
val p: String
    get() = _p.getValue(this, ::p) // Volání getValue na delegátovi
*/

Delegující objekt musí mít odpovídající metody:

  • getValue(thisRef, property: KProperty<*>): T pro vlastnost typu T. thisRef je instance třídy, property metadata vlastnosti.
  • setValue(thisRef, property: KProperty<*>, value: T) pro měnitelnou vlastnost.

Výhody používání delegátů:

  • Opakované použití kódu: Obecná logika (lenivá inicializace, sledování změn) je přesunuta do samostatného delegáta a je opakovaně použitelná.
  • Zlepšení čitelnosti: Kód je méně objemný, boilerplate kód je skrytý uvnitř delegáta.
  • Modularita: Logika správy vlastností nebo implementace rozhraní je oddělena od hlavní logiky třídy.