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. Вопросы на собесе
- Какие виды делегатов есть в Kotlin?
- Как работает делегат на класс?
- На каком потоке исполняется lazy?
- Является ли lazy потокобезопасным?
- Как создать свой собственный делегат?