Открытые классы и подклассы
Часть раздела Объектно-ориентированное программирование путешествия по Kotlin на Coddy. Урок 17 из 57.
Наследование позволяет одному классу строиться на основе другого. Подкласс получает все свойства и методы своего суперкласса и может добавлять собственные. В Kotlin классы по умолчанию закрыты, поэтому класс нужно пометить как open, прежде чем другой класс сможет его расширить:
open class Animal(val name: String) {
fun describe() = "$name is an animal"
}
class Dog(name: String) : Animal(name) {
fun fetch() = "$name fetches the ball"
}Внутри main:
val rex = Dog("Rex")
println(rex.describe())
println(rex.fetch())Вывод:
Rex is an animal
Rex fetches the ballclass Dog(name: String) : Animal(name) означает, что Dog наследуется от Animal и передаёт name конструктору суперкласса. У параметра нет val, потому что это свойство уже существует в Animal. Класс, который не является open, нельзя расширить:
class Plant(val name: String)
// class Tree(name: String) : Plant(name) // ошибка: этот тип является final, поэтому от него нельзя наследоваться
open class Vehicle(val wheels: Int)
class Bike : Vehicle(2) // передаёт фиксированное значение
class Truck(val load: Int) : Vehicle(6) // добавляет собственное свойствоDog — это Animal, поэтому экземпляр подкласса можно использовать везде, где ожидается тип суперкласса. Один List<Animal> может содержать собак, кошек и обычных животных, и у каждого элемента есть члены Animal:
open class Animal(val name: String) {
fun describe() = "$name is an animal"
}
class Dog(name: String) : Animal(name)
class Cat(name: String, val indoor: Boolean) : Animal(name)Внутри main:
val pets: List<Animal> = listOf(Dog("Rex"), Cat("Tom", true), Animal("Generic"))
for (p in pets) println(p.describe())Вывод:
Rex is an animal
Tom is an animal
Generic is an animalНаследование моделирует отношение «является»: собака — это животное, сберегательный счёт — это счёт. Если один класс только использует другой (у автомобиля есть двигатель), вместо этого добавь ему свойство такого типа. В Kotlin классы по умолчанию закрыты, поэтому класс, предназначенный для расширения, объявляет об этом с помощью open, а поведение всех остальных классов остаётся защищённым от подклассов.
open class Account(val owner: String)
class SavingsAccount(owner: String) : Account(owner) // является: наследование
class Engine(val horsepower: Int)
class Car(val engine: Engine) // имеет: свойствоЗадание
ЛегкоManager дублирует то, что уже есть у Employee. Сделай Employee открытым классом, а Manager — его подклассом: Manager(name: String, salary: Int) передаёт оба значения в Employee и оставляет только то, что является новым: приватный список имён подчинённых с методами addReport(name) и teamSize(). В Employee метод raise(percent) увеличивает зарплату на указанный процент с округлением вниз, а describe() возвращает Ada earns 5500.
Предоставленный код создаёт менеджера на основе первой строки (name,salary), добавляет каждое последующее имя как имя подчинённого, повышает зарплату на 10% и выводит Ada earns 5500 and leads 2, а затем проверяет, что менеджер является экземпляром Employee.
Твой код нужно разместить в Employee.kt и Manager.kt. В Main.kt находится предоставленный код ввода/вывода, его нельзя редактировать.
Попробуйте сами
fun main() {
// Предоставленный код ввода-вывода: оставьте его без изменений
val input = generateSequence(::readLine).toList()
val (name, salary) = input[0].split(",")
val boss = Manager(name, salary.toInt())
for (report in input.drop(1)) boss.addReport(report)
boss.raise(10)
println("${boss.describe()} and leads ${boss.teamSize()}")
println("a manager is an employee: ${(boss as Any) is Employee}")
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Классы и объекты
Работа с файламиОпределение классовПервичные конструкторыБлоки init и валидацияВторичные конструкторыПовторение — читательский билет4Наследование
Открытые классы и подклассыПереопределение членовsuper и конструкторыАбстрактные классыПовторение — каталог сотрудников7Специальные классы
Классы данныхКлассы перечисленийЗапечатанные иерархииequals, hashCode, toStringПовторение — трекер заказов10Паттерны проектирования. Часть 2
Делегирование с помощью byПаттерн декораторПаттерн строительПаттерн состояние2Свойства и инкапсуляция
Пользовательские аксессорыМодификаторы видимостиПриватные сеттерыlazy и lateinitПовторение — банковский счёт5Интерфейсы
Объявление интерфейсовМетоды по умолчаниюМножественные интерфейсыИнтерфейсы как типыПовторение — способы оплаты8Обобщения
Обобщённые функцииОбобщённые классыОграничения типовВариативность с in и outПовторение — очередь с приоритетом11Проект: Управление библиотекой
Книги и читателиВыдача книг3Объекты и компаньоны
Объявления объектовОбъекты-компаньоныКонстанты с constОбъектные выраженияПовторение — билетная касса6Полиморфизм
Динамическая диспетчеризацияПроверка типов и умные приведения типовwhen с типамиФункции-расширенияПовторение — смотритель зоопарка9Паттерны проектирования. Часть 1
Паттерн «Одиночка»Фабричный паттернПаттерн «Наблюдатель»Паттерн «Стратегия»Потренируйтесь самостоятельно: Песочница Kotlin