Делегирование членам
Составляйте поведение
«Делегирование членам» — бесплатный урок Kotlin Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Kotlin Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Kotlin Academy содержит 4 уроков всего.
Составление поведения
Реальным объектам часто требуется объединять несколько возможностей. Вместо наследования от множества источников можно делегировать каждую возможность отдельному объекту-члену.
Две роли, один класс
Предположим, класс должен поддерживать операции read и write. Определите два интерфейса и делегируйте каждый своей реализации.
interface Reader { fun read(): String }
interface Writer { fun write(s: String): String }
class FileReader : Reader { override fun read() = "contents" }
class FileWriter : Writer { override fun write(s: String) = "wrote " + s }
class FileIO(r: Reader, w: Writer) : Reader by r, Writer by w
fun main() {
val io = FileIO(FileReader(), FileWriter())
println(io.read())
println(io.write("data"))
}Несколько делегатов
Класс может одновременно делегировать несколько интерфейсов, каждый — отдельному члену. Класс объединяет их поведение без наследования.
interface Logger { fun log(m: String): String }
interface Validator { fun valid(m: String): Boolean }
class ConsoleLogger : Logger { override fun log(m: String) = "LOG: " + m }
class LengthValidator : Validator { override fun valid(m: String) = m.isNotEmpty() }
class Service(l: Logger, v: Validator) : Logger by l, Validator by v
fun main() {
val s = Service(ConsoleLogger(), LengthValidator())
println(s.valid("hi"))
println(s.log("started"))
}Делегат, сохранённый как член
Если нужно обращаться к делегату внутри переопределений, сохраните его как свойство конструктора. Один и тот же экземпляр будет использоваться и для перенаправления, и в Вашем собственном коде.
interface Cache { fun get(k: String): String }
class MapCache : Cache {
override fun get(k: String) = "value-of-" + k
}
class TracingCache(private val inner: Cache) : Cache by inner {
override fun get(k: String): String {
println("lookup " + k)
return inner.get(k)
}
}
fun main() {
println(TracingCache(MapCache()).get("id"))
}Сочетание делегирования и собственного состояния
Класс, использующий делегирование, может добавлять собственные свойства и методы наряду с перенаправляемыми, расширяя составной объект.
interface Engine { fun start(): String }
class V8 : Engine { override fun start() = "vroom" }
class Car(e: Engine) : Engine by e {
var doors = 4
fun honk() = "beep"
}
fun main() {
val c = Car(V8())
println(c.start())
println(c.honk())
println(c.doors)
}Замена реализаций
Поскольку делегат — всего лишь член класса, можно создавать одну и ту же обёртку с разными базовыми реализациями, выбирая поведение во время выполнения.
interface Notifier { fun send(msg: String): String }
class EmailNotifier : Notifier { override fun send(msg: String) = "email: " + msg }
class SmsNotifier : Notifier { override fun send(msg: String) = "sms: " + msg }
class Alerts(n: Notifier) : Notifier by n
fun main() {
println(Alerts(EmailNotifier()).send("hi"))
println(Alerts(SmsNotifier()).send("hi"))
}Делегирование свойству
Выражением после by может быть любое выражение, вычисляемое один раз, включая вызов конструктора. Это необязательно должен быть параметр.
interface Greeter { fun greet() = "hi" }
class DefaultGreeter : Greeter
class Page : Greeter by DefaultGreeter()
fun main() {
println(Page().greet())
}Как избежать проблемы ромба
Множественное наследование поведения невозможно для классов, но делегирование нескольких интерфейсов отдельным членам позволяет аккуратно обойти классическую проблему ромба.
interface A { fun a() = "A" }
interface B { fun b() = "B" }
class AImpl : A
class BImpl : B
class Combined : A by AImpl(), B by BImpl()
fun main() {
val c = Combined()
println(c.a() + c.b())
}Проектирование для композиции
Чтобы хорошо использовать композицию:
- Определяйте небольшие специализированные интерфейсы
- Предоставляйте повторно используемые реализации
- Делегируйте каждую роль в составном классе
Так классы остаются гибкими и удобными для тестирования.
Итоги делегирования членам
Делегирование объектам-членам позволяет классу собирать поведение из отдельных частей. Можно объединять множество интерфейсов, выборочно переопределять их члены, заменять реализации и добавлять собственное состояние — всё это без наследования.
Далее: прямое сравнение
Вы увидели, насколько гибким бывает делегирование. В следующем уроке мы напрямую сравним делегирование с наследованием, чтобы Вы знали, когда выбирать каждый из этих подходов.
Быстрая проверка
Проверьте, насколько хорошо Вы понимаете делегирование членам.
Итоги
Вы изучили делегирование членам:
- Делегирование нескольких интерфейсов отдельным объектам
- Выборочное переопределение и добавление собственного состояния
- Замена реализаций при создании объекта
- Избежание проблем множественного наследования
Далее: делегирование и наследование.
Часто задаваемые вопросы
Урок «Делегирование членам» бесплатный?
Да — полный текст урока «Делегирование членам» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Kotlin Academy, подпишись на CoddyKit PRO. Курс Kotlin Academy содержит 4 уроков всего.
Чему я научусь в уроке «Делегирование членам»?
Составляйте поведение Ты практикуешь Kotlin Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Kotlin Academy?
Предыдущий опыт не требуется. Kotlin Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Делегирование членам»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Kotlin Academy?
Да. Каждый урок Kotlin Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Ключевое слово by
- Делегирование членам
- Делегирование и наследование
- Практические шаблоны