0Pricing
Kotlin Academy · Урок

Делегирование и наследование

Выбирайте композицию

«Делегирование и наследование» — бесплатный урок Kotlin Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Kotlin Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Kotlin Academy содержит 4 уроков всего.

Два способа повторного использования

Наследование и делегирование позволяют повторно использовать поведение. Наследование означает, что класс является разновидностью другого класса. Делегирование означает, что класс содержит объект-сотрудник, которому он передаёт вызовы.

Классическая рекомендация: предпочитайте композицию наследованию.

Пример наследования

При наследовании подкласс расширяет базовый класс и переопределяет его члены. В языке Kotlin базовый класс должен быть open.

open class Animal {
    open fun sound() = "..."
}

class Dog : Animal() {
    override fun sound() = "woof"
}

fun main() {
    println(Dog().sound())
}

Пример делегирования

То же повторное использование с помощью делегирования: поведение находится в члене, которому класс переадресует вызовы.

interface Sound { fun sound(): String }
class Bark : Sound { override fun sound() = "woof" }

class Dog(s: Sound) : Sound by s

fun main() {
    println(Dog(Bark()).sound())
}

Хрупкий базовый класс

Наследование создаёт тесную связанность подкласса с внутренним устройством родительского класса. Изменение в базовом классе может незаметно нарушить работу подклассов — это проблема хрупкого базового класса. Делегирование зависит только от интерфейса.

Инкапсуляция

Подкласс может обращаться к защищённым членам и переопределять точки расширения, заглядывая во внутреннее устройство родительского класса. Делегирующий класс видит только публичный интерфейс и сохраняет инкапсуляцию.

interface Counter { fun increment(): Int }

class SimpleCounter : Counter {
    private var n = 0
    override fun increment(): Int { n++; return n }
}

class GuardedCounter(private val c: Counter) : Counter by c {
    override fun increment(): Int {
        println("incrementing")
        return c.increment()
    }
}

fun main() {
    val g = GuardedCounter(SimpleCounter())
    println(g.increment())
    println(g.increment())
}

Гибкость во время выполнения

Наследование фиксирует родительский класс во время компиляции. Делегирование позволяет подставлять разные реализации во время выполнения и упрощает тестирование с помощью подставных реализаций.

interface Clock { fun now(): Int }
class RealClock : Clock { override fun now() = 100 }
class FakeClock : Clock { override fun now() = 0 }

class Timer(c: Clock) : Clock by c

fun main() {
    println(Timer(RealClock()).now())
    println(Timer(FakeClock()).now()) // easy to test
}

Несколько вариантов поведения

Класс может расширять только одного родителя, но делегировать работу множеству интерфейсов. Делегирование хорошо подходит для объединения нескольких возможностей.

interface Walk { fun walk() = "walking" }
interface Swim { fun swim() = "swimming" }
class Walker : Walk
class Swimmer : Swim

class Amphibian : Walk by Walker(), Swim by Swimmer()

fun main() {
    val a = Amphibian()
    println(a.walk() + ", " + a.swim())
}

Когда подходит наследование

Наследование по-прежнему уместно для настоящего отношения is-a при наличии стабильной и спроектированной для расширения иерархии: семейств запечатанных типов, базовых классов фреймворка и полиморфизма на основе общего абстрактного типа.

sealed class Shape
class Circle(val r: Double) : Shape()
class Square(val s: Double) : Shape()

fun area(shape: Shape) = when (shape) {
    is Circle -> 3.14 * shape.r * shape.r
    is Square -> shape.s * shape.s
}

fun main() {
    println(area(Circle(2.0)))
}

Когда подходит делегирование

Выбирайте делегирование, если хотите:

  • Повторно использовать поведение в несвязанных типах
  • Объединять несколько возможностей
  • Сохранять слабую связанность и упрощать тестирование
  • Оборачивать и декорировать существующие реализации

Сравнение

Наследование: один родитель, тесная связанность, фиксация во время компиляции, is-a. Делегирование: множество взаимодействующих объектов, слабая связанность, возможность замены во время выполнения, has-a. Kotlin делает делегирование с помощью by почти бесплатным, склоняя выбор в пользу композиции.

Практическое правило по умолчанию

Хорошее правило: начинайте с делегирования. Переходите к наследованию только тогда, когда действительно появляется стабильная иерархия is-a. Это сохраняет гибкость проектирования и устойчивость к изменениям.

Быстрая проверка

Проверьте, насколько хорошо Вы понимаете разницу между делегированием и наследованием.

Итоги

Вы сравнили два подхода:

  • Наследование: is-a, один родитель, тесная связанность
  • Делегирование: has-a, множество взаимодействующих объектов, слабая связанность
  • Предпочитайте композицию; используйте наследование для стабильных иерархий is-a

Далее: практические шаблоны декоратора с делегированием.

Часто задаваемые вопросы

Урок «Делегирование и наследование» бесплатный?

Да — полный текст урока «Делегирование и наследование» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Kotlin Academy, подпишись на CoddyKit PRO. Курс Kotlin Academy содержит 4 уроков всего.

Чему я научусь в уроке «Делегирование и наследование»?

Выбирайте композицию Ты практикуешь Kotlin Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Kotlin Academy?

Предыдущий опыт не требуется. Kotlin Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Делегирование и наследование»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Kotlin Academy?

Да. Каждый урок Kotlin Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Ключевое слово by
  2. Делегирование членам
  3. Делегирование и наследование
  4. Практические шаблоны
← Назад к Kotlin Academy