Классы. Наследование

Классы. Наследование


В главное меню

Наследование — это принцип объектно-ориентированного программирования, помогающий определить иерархические отношения между типами.

Чтобы получить представление о наследовании, рассмотрим пример, не имеющий прямого отношения к программированию. У легковых и грузовых автомобилей есть много общего: колеса, двигатель и т. д. Но есть и различия. Использование наследования позволяет объединить одинаковые черты в общий класс Venicle, что даст возможность не реализовывать повторно Wheel (колеса) и Engine (двигатель) для легковых и грузовых автомобилей. Легковые и грузовые автомобили унаследуют эти общие признаки, а дальше каждый из них будет определять уникальные для себя признаки.


class Room  (val name: String) {
    fun description() = "Room: $name"

    fun load() = "Nothing much to see here..."
}


Создание подкласса

Подкласс обладает всеми чертами наследуемого класса, который также называют родительским классом, или суперклассом.

Не каждый класс, который вы напишете, сможет стать частью иерархии, и даже более того, у них есть ограничение, которое запрещает наследование по умолчанию. Чтобы класс можно было унаследовать, его надо отметить ключевым словом open.
open class Room  (val name: String) {
    fun description() = "Room: $name"

    fun load() = "Nothing much to see here..."
}

Создание класса наследника

class TownSquare : Room("TownSquare")

В данном случае TownSquare — это версия Room с названием "Town Square"

Другой способ добавить отличий подкласса от предка — это переопределение.

open class Room  (val name: String) {
    fun description() = "Room: $name"

    open fun load() = "Nothing much to see here..."
}

class TownSquare : Room("TownSquare") {
    override fun load() = "The villagers rally and cheer as you enter!"
}

Рассмотрим следующий заголовок функции:

fun drawBlueprint(room: Room)

drawBlueprint принимает Room в качестве параметра. Она также может принять любой подкласс Room, потому что любой подкласс будет обладать всеми характеристиками Room. Полиморфизм позволяет писать функции, которым важны только возможности класса, а не их реализации.

Иерархия типов в языке Kotlin

Все классы в Kotlin наследуют общий суперкласс, известный как Any, без необходимости явного указания на это в вашем коде

fun printIsSourceOfBlessings(any: Any) {
    val isSourceOfBlessings = if (any is Player) {
        any.isBlessed
    } else {
        (any as Room).name == "Fount of Blessings"
    }
    println("$any is a source of blessings: $isSourceOfBlessings")
}

printIsSourceOfBlesings принимает аргумент типа Any и использует условный оператор для проверки типа переданного аргумента. В конце она выводит результаты проверки. Здесь используется несколько новых идей, которые мы рассмотрим чуть позже.

Оператор as обозначает приведение типа. Он говорит нам: «Чтобы выполнить это выражение, переменную any следует считать экземпляром типа Room». Выражение в данном случае — это ссылка на свойство name класса Room, значение которого сравнивается со строкой "Fount of Blessings".

final

Допустим, вы хотите, чтобы любой подкласс TownSquare мог менять свое описание description, но не способ загрузки load.

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

open class TownSquare : Room("TownSquare") {
    override val dangerLevel = super.dangerLevel - 3

    private var bellSound = "GWONG"

    final override fun load() = "The villagers rally and cheer as you enter!\n${ringBell()}"
    open fun ringBell() = "The bell tower announces your arrival. $bellSound"
}

Теперь любой подкласс TownSquare сможет переопределить функцию description, но не load, потому что перед ней стоит ключевое слово final.

protected

Это вариант, ограничивающий область видимости члена класса самим классом и любыми его подклассами.

open class Room  (val name: String) {
    protected open val dangerLevel = 5

    fun description() = "Room: $name\nDanger level: $dangerLevel"

    open fun load() = "Nothing much to see here..."
}

open class TownSquare : Room("TownSquare") {
    override val dangerLevel = super.dangerLevel - 3
}

Подклассы Room могут изменять dangerLevel, чтобы выразить, насколько опасна (или не очень) конкретная комната, но в целом свойство dangerLevel должно быть доступно только в Room и его подклассах. Это идеальный случай для использования ключевого слова protected: вы хотите предоставить доступ к свойству только классу, в котором оно объявлено, и его подклассам.

Для блога


Report Page