В программировании делегирование — это паттерн проектирования, при котором объект передает выполнение задачи другому вспомогательному объекту. В Kotlin этот механизм встроен на уровне языка, что позволяет избежать написания шаблонного кода (boilerplate).
В Kotlin существует два основных вида делегирования:
- Делегирование классов (Class Delegation).
- Делегирование свойств (Property Delegation).
1. Делегирование классов
Этот механизм позволяет реализовать интерфейс, передавая все его методы другому объекту. Это отличная альтернатива наследованию.
Представьте, что у нас есть интерфейс Printer и его реализация. Мы хотим создать класс SmartPrinter, который тоже умеет печатать, но использует для этого уже готовую логику.
interface Printer {
fun printMessage(message: String)
}
class PlainPrinter : Printer {
override fun printMessage(message: String) {
println("Печать: $message")
}
}
// Используем ключевое слово 'by' для делегирования
class SmartPrinter(printer: Printer) : Printer by printer
fun main() {
val printer = PlainPrinter()
val smartPrinter = SmartPrinter(printer)
smartPrinter.printMessage("Привет, Kotlin!")
// Выведет: Печать: Привет, Kotlin!
}
Почему это круто? Вам не нужно переопределять каждый метод интерфейса вручную. Ключевое слово by говорит компилятору: «сгенерируй все методы интерфейса Printer и внутри них вызови методы объекта printer».
2. Делегирование свойств
Делегирование свойств позволяет вынести логику работы с геттером (get) и сеттером (set) в отдельный класс. Синтаксис выглядит так: val/var имяСвойства: Тип by Делегат.
Встроенные делегаты Kotlin
В стандартной библиотеке Kotlin уже есть несколько полезных делегатов:
А) Lazy (Ленивая инициализация)
Значение вычисляется только при первом обращении к свойству.
val heavyData: String by lazy {
println("Выполняем сложные вычисления...")
"Данные загружены"
}
fun main() {
println("Программа запущена")
println(heavyData) // Здесь произойдет вычисление
println(heavyData) // Здесь просто вернется готовый результат
}
Б) Observable (Наблюдатель)
Позволяет отслеживать изменения свойства.
import kotlin.properties.Delegates
class User {
var name: String by Delegates.observable("Без имени") { prop, old, new ->
println("Имя изменилось с '$old' на '$new'")
}
}
fun main() {
val user = User()
user.name = "Алексей" // Выведет лог изменения
user.name = "Иван"
}
3. Создание своего делегата
Вы можете написать собственный делегат. Для этого класс должен иметь оператор getValue (и setValue для var).
import kotlin.reflect.KProperty
class TrimDelegate {
private var value: String = ""
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return value
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: String) {
// Автоматически обрезаем пробелы при записи
value = newValue.trim()
}
}
class Person {
var name: String by TrimDelegate()
}
fun main() {
val person = Person()
person.name = " Дмитрий "
println("'${person.name}'") // Выведет: 'Дмитрий'
}
Зачем использовать делегаты?
Чистота кода: Вы избавляетесь от дублирования логики в геттерах и сеттерах.
Композиция вместо наследования: Делегирование классов позволяет гибко собирать функциональность объекта.
Повторное использование: Один раз написанный сложный делегат (например, для работы с Базой Данных или SharedPrefs) можно использовать во всем проекте.

