← Назад к вопросам

Какие знаешь типы Delegates?

2.2 Middle🔥 151 комментариев
#Kotlin основы#Архитектура и паттерны

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Типы 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 Coroutinesasync() для отложенных асинхронных вычислений .
  • Koin/ Dagger — делегаты для внедрения зависимостей:
val viewModel: MainViewModel by inject() // Koin
  • Android Jetpackby 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-код, но и позволяют создавать выразительные, легко поддерживаемые абстракции для управления состоянием объектов.

Какие знаешь типы Delegates? | PrepBro