Спадщина Котліна (з прикладами)

У цій статті ви дізнаєтесь про спадщину. Більш конкретно, що таке успадкування та як це реалізувати в Kotlin (за допомогою прикладів).

Спадкування - одна з ключових особливостей об’єктно-орієнтованого програмування. Це дозволяє користувачеві створити новий клас (похідний клас) з існуючого класу (базовий клас).

Похідний клас успадковує всі функції базового класу і може мати власні додаткові функції.

Перш ніж вдаватися до деталей про спадкування Котліна, ми рекомендуємо вам ознайомитися з цими двома статтями:

  • Клас і предмети Котліна
  • Котлін Первинний конструктор

Чому спадщина?

Припустимо, у вашій заявці ви хочете трьох персонажів - вчителя математики , футболіста та бізнесмена .

Оскільки всі герої - це особи, вони можуть ходити і говорити. Однак вони також мають деякі особливі навички. Вчитель математики може викладати математику , футболіст може грати у футбол, а бізнесмен вести бізнес .

Ви можете індивідуально створити три класи, які можуть ходити, розмовляти та виконувати свої особливі навички.

У кожному з класів ви б копіювали один і той же код для прогулянки та розмови для кожного персонажа.

Якщо ви хочете додати нову функцію - їжте, вам потрібно застосувати однаковий код для кожного символу. Це може легко спричинити помилки (при копіюванні) та повторювані коди.

Було б набагато простіше, якби ми мали Personклас із такими основними функціями, як розмова, прогулянки, їжа, сон та додавання спеціальних навичок до цих функцій відповідно до наших персонажів. Це робиться за допомогою успадкування.

Використання успадкування, тепер ви не реалізуєте один і той же код walk(), talk()і eat()для кожного класу. Вам просто потрібно успадкувати їх.

Отже, для MathTeacher(похідного класу) ви успадковуєте всі функції Person(базового класу) і додаєте нову функцію teachMath(). Так само для Footballerкласу ви успадковуєте всі функції Personкласу, додаєте нову функцію playFootball()тощо.

Це робить ваш код чистішим, зрозумілішим та розширюванішим.

Важливо пам'ятати: При роботі з успадкуванням, кожен похідний клас повинен задовольняти умові чи «це» базовий клас чи ні. У наведеному вище прикладі MathTeacher є a Person , Footballer є a Person . Ви не можете мати щось на зразок, Businessman є a Business .

Спадщина Котліна

Спробуємо реалізувати наведене вище обговорення в коді:

 відкритий клас Person (вік: Int) (// код для прийому їжі, розмов, ходьби) клас MathTeacher (вік: Int): Person (вік) (// інші особливості вчителя математики) клас Футболіст (вік: Int): Person ( вік) (// інші особливості футболіста) клас Бізнесмен (вік: Int): Особа (вік) (// інші особливості бізнесмена)

Тут, Personє базовим класом, і класи MathTeacher, Footballerі Businessmanє похідними від класу Person.

Зверніть увагу, ключове слово openперед базовим класом, Person. Це важливо.

За замовчуванням класи в Kotlin є остаточними. Якщо ви знайомі з Java, ви знаєте, що кінцевий клас не можна підкласувати. Використовуючи відкриту анотацію для класу, компілятор дозволяє отримувати з неї нові класи.

Приклад: спадкування Котліна

 open class Person(age: Int, name: String) ( init ( println("My name is $name.") println("My age is $age") ) ) class MathTeacher(age: Int, name: String): Person(age, name) ( fun teachMaths() ( println("I teach in primary school.") ) ) class Footballer(age: Int, name: String): Person(age, name) ( fun playFootball() ( println("I play for LA Galaxy.") ) ) fun main(args: Array) ( val t1 = MathTeacher(25, "Jack") t1.teachMaths() println() val f1 = Footballer(29, "Christiano") f1.playFootball() )

Коли ви запускаєте програму, результат буде:

Мене звуть Джек. Мій вік 25, я викладаю в початковій школі. Мене звати Кріштіану. Мені 29 років, я граю за LA Galaxy.

Тут два класи MathTeacherі Footballerпохідні від Personкласу.

Первинний конструктор Personкласу оголосив дві властивості: вік та ім'я та має блок ініціалізації. До блоку ініціалізатора (і функцій-членів) базового класу Personможуть отримати доступ об'єкти похідних класів ( MathTeacherі Footballer).

Похідні класи MathTeacherі Footballerмають власні функції-члени teachMaths()і playFootball()відповідно. Ці функції доступні лише з об'єктів відповідного класу.

Коли MathTeacherстворюється об'єкт класу t1 ,

 val t1 = MathTeacher (25, "Джек")

Параметри передаються первинному конструктору. У Kotlin initблок викликається при створенні об'єкта. Оскільки MathTeacherпоходить від Personкласу, він шукає блок ініціалізатора в базовому класі (Person) і виконує його. Якби MathTeacherбув блок init, компілятор також виконав би блок ініціювання похідного класу.

Далі teachMaths()функція для об’єкта t1викликається за допомогою t1.teachMaths()оператора.

Програма працює так само , коли об'єкт f1з Footballerкласу створюється. Він виконує блок init базового класу. Потім playFootball()метод Footballerкласу викликається за допомогою оператора f1.playFootball().

Важливі примітки: Kotlin Inheritance

  • Якщо клас має первинний конструктор, база повинна бути ініціалізована за допомогою параметрів первинного конструктора. У наведеній вище програмі обидва похідні класи мають два параметри ageі name, і обидва ці параметри ініціалізуються в первинному конструкторі в базовому класі.
    Ось ще один приклад:
     open class Person(age: Int, name: String) ( // some code ) class Footballer(age: Int, name: String, club: String): Person(age, name) ( init ( println("Football player $name of age $age and plays for $club.") ) fun playFootball() ( println("I am playing football.") ) ) fun main(args: Array) ( val f1 = Footballer(29, "Cristiano", "LA Galaxy") )  
    Тут основний конструктор похідного класу має 3 параметри, а базовий клас має 2 параметри. Зауважте, що обидва параметри базового класу ініціалізовані.
  • У разі відсутності первинного конструктора, кожен базовий клас повинен ініціалізувати базу (за допомогою ключового слова super) або делегувати іншому конструктору, який це робить. Наприклад,
     fun main(args: Array) ( val p1 = AuthLog("Bad Password") ) open class Log ( var data: String = "" var numberOfData = 0 constructor(_data: String) ( ) constructor(_data: String, _numberOfData: Int) ( data = _data numberOfData = _numberOfData println("$data: $numberOfData times") ) ) class AuthLog: Log ( constructor(_data: String): this("From AuthLog -> + $_data", 10) ( ) constructor(_data: String, _numberOfData: Int): super(_data, _numberOfData) ( ) )
    Щоб дізнатись більше про те, як працює ця програма, відвідайте Kotlin Secondary Constructor.

Заміна функцій і властивостей членів

If the base class and the derived class contains a member function (or property) with the same name, you can need to override the member function of the derived class using override keyword, and use open keyword for the member function of the base class.

Example: Overriding Member Function

 // Empty primary constructor open class Person() ( open fun displayAge(age: Int) ( println("My age is $age.") ) ) class Girl: Person() ( override fun displayAge(age: Int) ( println("My fake age is $(age - 5).") ) ) fun main(args: Array) ( val girl = Girl() girl.displayAge(31) )

When you run the program, the output will be:

 My fake age is 26.

Here, girl.displayAge(31) calls the displayAge() method of the derived class Girl.

You can override property of the base class in similar way.

Visit how Kotlin getters and setters work in Kotlin before you check the example below.

 // Empty primary constructor open class Person() ( open var age: Int = 0 get() = field set(value) ( field = value ) ) class Girl: Person() ( override var age: Int = 0 get() = field set(value) ( field = value - 5 ) ) fun main(args: Array) ( val girl = Girl() girl.age = 31 println("My fake age is $(girl.age).") )

When you run the program, the output will be:

 My fake age is 26.

As you can see, we have used override and open keywords for age property in derived class and base class respectively.

Calling Members of Base Class from Derived Class

Ви можете викликати функції (і доступ до властивостей) базового класу з похідного класу за допомогою superключового слова. Ось як:

 open class Person() ( open fun displayAge(age: Int) ( println("My actual age is $age.") ) ) class Girl: Person() ( override fun displayAge(age: Int) ( // calling function of base class super.displayAge(age) println("My fake age is $(age - 5).") ) ) fun main(args: Array) ( val girl = Girl() girl.displayAge(31) )

Коли ви запускаєте програму, результат буде:

 Мій вік - 31. Мій фальшивий вік - 26 років.

Цікаві статті...