Делегирование в Kotlin
Делегирование — способ переиспользовать поведение, не наследуясь. Вместо class B : A() вы пишете class B(p: I) : I by p: B реализует интерфейс I, но каждый его метод перенаправляет объекту p. Перенаправляющие методы за вас пишет компилятор, поэтому это композиция вместо наследования — предпочтительный способ переиспользования кода без хрупкой иерархии классов.
Простота обманчива, и на собеседовании проверяют именно углы. Ключевое слово by — это не наследование и не by lazy (делегирование свойств — отдельный механизм). Явный override в классе всегда берёт верх над делегатом. А сам делегат вызывает свои методы и не видит переопределений производного класса — это «проблема self», источник тихих багов. Полная карта — в слое ниже.
Карта темы
- Делегирование интерфейса by — как
byперенаправляет методы объекту, почему это композиция, приоритетoverrideи проблема self.
Частые ошибки и ловушки
| Ошибка | Последствие |
|---|---|
Понимать by как наследование | Неверная модель — by перенаправляет методы, а не строит иерархию |
Путать делегирование интерфейса с by lazy | Это разные механизмы одного ключевого слова |
Думать, что делегат p копируется | Он хранится по ссылке — общее состояние с внешним владельцем |
Считать, что метод делегата перекроет явный override | Наоборот — override класса всегда берёт верх |
Ждать, что делегат увидит override производного класса | Делегат зовёт свои методы — переопределений класса он не видит |
| Делегировать один интерфейс двум объектам | Конфликт общего метода — класс обязан переопределить его явно |
Значение для собеседований
Тему спрашивают как проверку того, отличаете ли вы композицию от наследования и понимаете ли, что делегат — отдельный объект со своим this. Кандидат, который говорит «by генерирует перенаправляющие методы, но явный override их перекрывает, а делегат зовёт свои методы, не видя моих», сразу опережает «by — это как extends».
Что обычно проверяют:
- Что делает
by— перенаправление всех методов интерфейса хранимому объекту. - Что это композиция вместо наследования и почему её часто предпочитают.
- Приоритет — явный
overrideкласса берёт верх над делегатом. - Проблему self — делегат не видит переопределений производного класса.
Типичный неверный ответ: «by делает B подклассом p и наследует его поля» или «делегат всегда побеждает override». На деле by — перенаправление вызовов хранимому по ссылке объекту, а override в самом классе всегда сильнее делегата.