Какие знаешь типы Delegates?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Типы Property Delegates в Kotlin
В Kotlin property delegates — это мощный механизм, позволяющий делегировать логику геттеров/сеттеров свойств внешним объектам. Это реализуется через конвенцию: класс делегата должен предоставить методы getValue() и/или setValue(). Вот основные встроенные и часто используемые типы делегатов:
1. lazy() — ленивая инициализация
Наиболее популярный делегат. Инициализация свойства происходит только при первом обращении, а результат кэшируется для последующих вызовов. Потокобезопасен по умолчанию.
val heavyResource: Resource by lazy {
println("Вычисляю тяжёлый ресурс")
Resource.load()
}
// Использование с разными режимами потокобезопасности
val nonThreadSafe: String by lazy(LazyThreadSafetyMode.NONE) {
"Небезопасно, но быстро"
}
2. observable() и vetoable() — наблюдаемые свойства
Оба делегата позволяют реагировать на изменения значения свойства:
observable()— уведомляет о изменении после того, как оно произошлоvetoable()— позволяет "ветоить" изменение до его применения
import kotlin.properties.Delegates
var name: String by Delegates.observable("Имя") { property, old, new ->
println("$old → $new")
}
var age: Int by Delegates.vetoable(0) { _, old, new ->
new >= 0 // Отклоняет отрицательные значения
}
3. notNull() — отложенная инициализация non-null свойства
Гарантирует, что свойство будет инициализировано до первого использования, иначе выбрасывает IllegalStateException. Альтернатива lateinit var для примитивных типов.
var importantId: Int by Delegates.notNull<Int>()
fun init(id: Int) {
importantId = id // Должно быть установлено до использования
}
4. Стандартные делегаты для Map и MutableMap
Позволяют использовать Map как делегированное хранилище для свойств. Имена свойств становятся ключами map.
class User(map: Map<String, Any>) {
val name: String by map
val age: Int by map
}
val user = User(mapOf("name" to "Алексей", "age" to 30))
println(user.name) // Алексей
5. Custom Delegates — пользовательские делегаты
Вы можете создавать собственные делегаты, реализуя интерфейсы ReadOnlyProperty (для val) или ReadWriteProperty (для var).
class LoggingDelegate<T> : ReadWriteProperty<Any?, T> {
private var value: T? = null
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
println("Чтение ${property.name}: $value")
return value ?: throw IllegalStateException()
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
println("Запись ${property.name}: $value")
this.value = value
}
}
var loggedProperty: String by LoggingDelegate()
6. Делегаты из сторонних библиотек
- Kotlinx Coroutines —
async()для отложенных асинхронных вычислений . - Koin/ Dagger — делегаты для внедрения зависимостей:
val viewModel: MainViewModel by inject() // Koin
- Android Jetpack —
by viewModels()для создания ViewModel
Практическое применение и преимущества
Основные преимущества делегатов:
- Инкапсуляция повторяющейся логики (валидация, кэширование, логирование)
- Улучшение читаемости кода за счёт декларативного стиля
- Сокращение шаблонного кода в геттерах/сеттерах
- Легко переиспользуемые паттерны поведения свойств
Пример комплексного использования:
class Settings {
// Ленивая загрузка конфигурации
val config: Config by lazy { loadConfig() }
// Наблюдаемое свойство с валидацией
var username: String by Delegates.observable("") { _, old, new ->
if (new.length < 3) println("Слишком короткое имя")
}
// Хранение в SharedPreferences через кастомный делегат
var darkModeEnabled: Boolean by PreferenceDelegate("dark_mode", false)
}
Делегаты свойств — один из краеугольных камней Kotlin, демонстрирующий мощь декларативного программирования. Они не только сокращают boilerplate-код, но и позволяют создавать выразительные, легко поддерживаемые абстракции для управления состоянием объектов.