Sobes.tech
Middle

Можеш ли објаснити принцип рада делегата у класи у Kotlin-у?

sobes.tech АИ

Одговор од АИ

Делегат у Kotlin је објекат који преузима извршавање одређеног задатка или делегира позиве метода другом објекту.

Главни сценарији употребе:

  1. Делегирање својстава (Delegated Properties): Преношење управљања геттерима и сеттерима својства другом објекту.

    • lazy: Израчунавање вредности својства при првом приступу.
    • observable: Извршавање акције при промени вредности својства.
    • vetoable: Забрана промене вредности својства на основу услова.
    class Example {
        // Израчунава се само при првом приступу
        val lazyValue: String by lazy {
            println("Израчун" )
            "Здраво"
        }
    
        // Позива се при свакој промени вредности
        var name: String by Delegates.observable("<нема имена>") { prop, old, new ->
            println("Име се променило са $old на $new")
        }
    }
    
  2. Делегирање интерфејса (Class Delegation): Реализација интерфејса пренаслеђивањем позива метода другом објекту.

    interface Base {
        fun print()
    }
    
    class BaseImpl(val x: Int) : Base {
        override fun print() {
            println(x)
        }
    }
    
    // Реализује Base, делегирајући позиве BaseImpl
    class Derived(b: Base) : Base by b
    
    fun main() {
        val b = BaseImpl(10)
        Derived(b).print() // Исписује 10
    }
    
  3. Делегирање функција (Function Delegation): Иако нема јасну синтаксу за делегирање појединачних функција, као за својства или интерфејсе, ово се концептуално реализује кроз композицију и позиве метода другог објекта.

Како ради делегирање својстава:

Код Kotlin компајлер генерише помоћни код. За својство делегирано објекту delegate, компајлер генерише скривено својство и позива методе getValue и setValue (за променљива својства) на објекту delegate, преносећи потребни контекст (екземпляр класе, метаподаци својства).

// Псеудо-код пример, како компајлер обрађује: val p: String by delegate
/*
private val _p: Delegate<Any?, String> = delegate_initializer
val p: String
    get() = _p.getValue(this, ::p) // Позив `getValue` на делегату
*/

Делегатски објекат мора имати одговарајуће методе:

  • getValue(thisRef, property: KProperty<*>): T за својство типа T. thisRef је пример класе, property метаподаци својства.
  • setValue(thisRef, property: KProperty<*>, value: T) за променљиво својство.

Предности коришћења делегата:

  • Поновна употреба кода: Општа логика (ленива инициализација, праћење промена) се преноси у посебан делегат и може се користити више пута.
  • Побољшање читљивости: Код постаје мањи, boilerplate код је скривен унутар делегата.
  • Модуларност: Логика управљања својствима или имплементација интерфејса се одваја од главне логике класе.