Делегирование интерфейса с помощью оператора by позволяет классу перенаправлять все вызовы интерфейса определённому объекту-депутату. Это снижает дублирование кода и реализует паттерн компоновки (composition).
Пример:
interface Logger { fun log(message: String) } class ConsoleLogger: Logger { override fun log(message: String) = println("LOG: $message") } class Service(logger: Logger): Logger by logger { fun doWork() { log("Service is working") } } val service = Service(ConsoleLogger()) service.doWork() // LOG: Service is working
Отличия от делегирования свойств:
val/var x by ...) применяется к конкретному свойству и требует реализации интерфейса делегата (например, ReadWriteProperty).Плюсы:
Минусы:
Чем делегирование интерфейса (
by) отличается от реализации интерфейса с передачей объекта через поле?
Ответ:
Делегирование (через by) автоматически реализует все методы интерфейса через делегат-объект. Если же просто хранить объект-делегат как поле и вызывать его методы вручную, то требуется вручную прописывать каждый метод интерфейса — что приводит к дублированию и ошибкам. Кроме того, делегирование через by даёт больше читаемости и меньше boilerplate-кода:
// Без делегирования class Service2(private val logger: Logger): Logger { override fun log(message: String) = logger.log(message) }
История
На проекте пытались реализовать паттерн декоратора для интерфейса Logger руками, забыли реализовать дополнительный метод интерфейса, который позже был добавлен в Logger. Проект компилировался, но новый функционал не работал, так как реализация была "пустышкой". Делегирование интерфейса через by позволило бы избежать этой ошибки: все новые методы автоматом реализует делегат.
История
При делегировании интерфейса через by, разработчик переопределил один из методов интерфейса, но забыл, что остальные методы всё равно идут через делегат. В результате часть функционала работала "нестандартно" — ошибка долго не ловилась в логике бизнес-методов.
История
Пытались реализовать делегирование нескольких интерфейсов с пересекающимися методами через by, возник конфликт — компилятор стал выдавать ошибку неоднозначности, пришлось явно переопределять дублирующиеся методы, иначе проект не собирался.