Delegates

https://kotlinlang.org/docs/delegation.html
https://kotlinlang.org/docs/delegated-properties.html

Delegates

Делегирование представляет паттерн объектно-ориентированного программирования, который позволяет одному объекту делегировать/перенаправить все запросы другому объекту. В определенной степени делегирование может выступать альтернативой наследованию.

• делегаты бывают 2 видов: на класс и на поле.

interface Messenger {
    fun send(message: String)
}

class InstantMessenger: Messenger {
    override fun send(message: String) {
        println(message)
    }
}

class SmartPhone(name: String, messenger: Messenger): Messenger by messenger

val telegram = InstantMessenger()
val pixel = SmartPhone("Pixel 5", telegram)
pixel.send("Hello World")

Delegated Properties

Делегированные свойства позволяют делегировать получение или присвоение их значения во вне - другому классу. Это позволяет нам добавить некоторую дополнительную логику при операции со свойствами, например, логгирование, какую-то предобработку и т.д

class Person(personName: String) {
    var name: String by LoggerDelegate(personName)
}

class LoggerDelegate(private var personName: String) {

    operator fun getValue(thisRef: Person, property: KProperty<*>): String {
        return personName
    }

    operator fun setValue(thisRef: Person, property: KProperty<*>, value: String) {
        personName = value
    }
}

val tom = Person("Tom")
tom.name = "Bob"
println(tom.name)

by

Используется для реализации делегирования.

lazy

Инициализирует свойство лениво. Это значит, что свойство будет инициализировано только при первом обращении к нему.

LazyThreadSafetyMode.SYNCHRONIZED Используется по умолчанию. Значение вычисляется только в одном потоке выполнения, и все остальные потоки могут видеть одно и то же значение.

LazyThreadSafetyMode.PUBLICATION Используется, когда синхронизация не требуется, тогда несколько потоков смогут исполнять вычисление одновременно.

LazyThreadSafetyMode.NONE Используется, если инициализация всегда будет происходить в одном потоке исполнения. Не гарантирует никакой потокобезопасности и связанных с этим дополнительных затрат.

val name: String by lazy(::getName)
val name: String by lazy(LazyThreadSafetyMode.PUBLICATION) {
    getName()
}

observable

Делегат, который позволяет следить за изменениями свойства и выполнять определенные действия при каждом изменении.

var observableValue: String by Delegates.observable("Initial") { prop, old, new ->
    println("Property ${prop.name} changed from $old to $new")
}

observableValue = "Changed" // Property observableValue changed from Initial to Changed

vetoable

Делегат, который позволяет проверять новые значения свойства перед его изменением и решать, следует ли принять это значение или нет.

var vetoableValue: Int by Delegates.vetoable(0) { _, old, new ->
    new >= 0 // Разрешаем только положительные значения
}

vetoableValue = 10 // Успешно изменено
println(vetoableValue) // 10

vetoableValue = -1 // Не изменяется, так как значение отрицательное
println(vetoableValue) // 10

notNull

Делегат, который предоставляет делегат, поддерживающий не-null значения. Обычно используется с nullable типами, чтобы гарантировать, что свойство не может быть null после инициализации.

var nonNullValue: String by Delegates.notNull()

nonNullValue = "Not null"
println(nonNullValue) // Not null

// nonNullValue = null // Ошибка компиляции

map

Делегат, который позволяет связать свойство с элементом из Map. Это полезно, когда вам нужно работать со свойствами, которые являются частью карты.

class User(val map: MutableMap<String, Any?>) {
    var name: String by map
    var age: Int by map
}

val user = User(mutableMapOf("name" to "John", "age" to 30))
println(user.name) // John
println(user.age) // 30

user.name = "Jane"
println(user.map["name"]) // Jane

Kotlin Delegates. Вопросы на собесе
  1. Какие виды делегатов есть в Kotlin?
  1. Как работает делегат на класс?
  1. На каком потоке исполняется lazy?
  1. Является ли lazy потокобезопасным?
  1. Как создать свой собственный делегат?