Наследование и полиморфизм
Изучите объектно-ориентированные принципы, такие как наследование, абстрактные классы и полиморфизм, в Scala.
«Наследование и полиморфизм» — бесплатный урок Scala for Backend Engineering & Functional Programming на CoddyKit. Это урок 2 из 2. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Scala for Backend Engineering & Functional Programming, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Scala for Backend Engineering & Functional Programming содержит 2 уроков всего.
Что такое наследование?
Наследование — это фундаментальная концепция объектно-ориентированного программирования (ООП), позволяющая новому классу наследовать свойства и поведение (методы) существующего класса.
Представьте это как отношение «родитель—потомок». Класс-«потомок» (подкласс) повторно использует код класса-«родителя» (суперкласса), экономя время и обеспечивая единообразие.
- Способствует повторному использованию кода.
- Устанавливает отношение «является» (например,
DogявляетсяAnimal). - Помогает организовать код в иерархию.
Ваш первый базовый класс
Давайте определим простой класс Animal. Это будет наш базовый класс, также называемый суперклассом или родительским классом. У него есть базовое поведение: говорить.
Запустите код, чтобы увидеть нашего обычного животного в действии!
class Animal {
val name: String = "Generic Animal"
def speak(): Unit = {
println(s"$name makes a sound.")
}
}
object Main {
def main(args: Array[String]): Unit = {
val myAnimal = new Animal()
myAnimal.speak()
}
}Расширение с помощью `extends`
Теперь создадим более конкретное животное — Dog. Dog является Animal, поэтому он может наследовать класс Animal с помощью ключевого слова extends.
Мы также можем переопределить метод speak, чтобы у Dog был собственный уникальный звук. Обратите внимание на ключевое слово override.
class Animal {
val name: String = "Generic Animal"
def speak(): Unit = {
println(s"$name makes a sound.")
}
}
class Dog extends Animal {
override val name: String = "Dog"
override def speak(): Unit = {
println(s"$name barks!")
}
}
object Main {
def main(args: Array[String]): Unit = {
val myAnimal = new Animal()
val myDog = new Dog()
myAnimal.speak() // Generic Animal makes a sound.
myDog.speak() // Dog barks!
}
}Возможности `override`
Ключевое слово override играет в Scala важную роль по нескольким причинам:
- Понятность: оно явно сообщает другим разработчикам, что этот метод или поле заменяет член суперкласса.
- Безопасность: компилятор проверяет, действительно ли вы переопределяете существующий член. Если вы допустите опечатку или метод суперкласса изменится, компилятор предупредит вас.
- Намерение: оно ясно показывает ваше намерение специализировать или изменить унаследованное поведение.
Всегда используйте override при переопределении унаследованных членов!
Полиморфизм: множество форм
Полиморфизм означает «множество форм». В ООП он позволяет обращаться с объектами разных классов как с объектами общего суперкласса.
Это означает, что у вас может быть переменная типа Animal, содержащая объект Dog, объект Cat или любой другой подкласс Animal. Когда вы вызываете метод у этой переменной, выполняется правильный метод, соответствующий фактическому типу объекта.
- Позволяет создавать гибкий и расширяемый код.
- Предоставляет единый интерфейс для разных типов данных.
- Достигается с помощью переопределения методов.
Полиморфизм на практике
Посмотрим на полиморфизм в действии. Мы создадим класс Cat, похожий на Dog. Затем поместим животных разных типов в список их общего супертипа Animal и вызовем их метод speak.
Обратите внимание: каждое животное издаёт собственный уникальный звук, хотя в списке все они рассматриваются как тип Animal.
class Animal {
val name: String = "Generic Animal"
def speak(): Unit = {
println(s"$name makes a sound.")
}
}
class Dog extends Animal {
override val name: String = "Dog"
override def speak(): Unit = {
println(s"$name barks!")
}
}
class Cat extends Animal {
override val name: String = "Cat"
override def speak(): Unit = {
println(s"$name meows!")
}
}
object Main {
def main(args: Array[String]): Unit = {
val animals: List[Animal] = List(
new Animal(),
new Dog(),
new Cat()
)
animals.foreach(_.speak())
}
}Знакомство с абстрактными классами
Иногда требуется базовый класс, который определяет общий интерфейс, но не предоставляет полной реализации для некоторых своих членов. Здесь на помощь приходят абстрактные классы.
Абстрактный класс:
- Не может быть создан напрямую (нельзя создать объект абстрактного класса).
- Может содержать абстрактные методы (методы без реализации) и конкретные методы (методы с реализацией).
- Служит шаблоном, который подклассы должны дополнить.
Создание абстрактных шаблонов
Давайте определим abstract class Shape. У каждой фигуры есть площадь, но формула её вычисления различается для каждой конкретной фигуры (круга, прямоугольника и т. д.).
Поэтому объявим area как абстрактный метод. Обратите внимание: у него нет тела (нет = { ... }). Подклассы должны будут предоставить его реализацию.
abstract class Shape {
def area: Double // Abstract method, no implementation
def describe(): Unit = {
println("This is a geometric shape.")
}
}
// You cannot do: new Shape() - it's abstract!
object Main {
def main(args: Array[String]): Unit = {
println("Abstract class Shape defined.")
println("Cannot instantiate Shape directly.")
}
}Конкретные реализации
Теперь создадим конкретные подклассы, такие как Circle и Rectangle, расширяющие наш abstract class Shape. Эти подклассы обязаны предоставить реализацию абстрактного метода area.
Они также наследуют конкретный метод describe() от Shape.
abstract class Shape {
def area: Double
def describe(): Unit = {
println("This is a geometric shape.")
}
}
class Circle(radius: Double) extends Shape {
override def area: Double = math.Pi * radius * radius
}
class Rectangle(width: Double, height: Double) extends Shape {
override def area: Double = width * height
}
object Main {
def main(args: Array[String]): Unit = {
val circle = new Circle(5)
val rectangle = new Rectangle(4, 6)
println(s"Circle area: ${circle.area}")
circle.describe()
println(s"Rectangle area: ${rectangle.area}")
rectangle.describe()
}
}Проверка: наследование и полиморфизм
Какие из следующих утверждений о наследовании и полиморфизме в Scala являются TRUE?
Повторение: наследование и полиморфизм
Отличная работа! В этом уроке мы изучили основные концепции ООП в Scala:
- Наследование: подклассы повторно используют код и устанавливают отношение «является» с суперклассами с помощью
extends. - Ключевое слово
override: необходимо для явного переопределения унаследованных методов и полей, обеспечивая безопасность типов и понятность кода. - Полиморфизм: возможность обращаться с объектами разных подклассов как с объектами общего суперкласса, создавая гибкий и расширяемый код.
- Абстрактные классы: шаблоны, которые нельзя создать напрямую; они используются для определения общих интерфейсов и абстрактных членов, реализуемых подклассами.
Эти концепции необходимы для создания хорошо структурированных и удобных в сопровождении приложений на Scala!
Часто задаваемые вопросы
Урок «Наследование и полиморфизм» бесплатный?
Да — полный текст урока «Наследование и полиморфизм» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Scala for Backend Engineering & Functional Programming, подпишись на CoddyKit PRO. Курс Scala for Backend Engineering & Functional Programming содержит 2 уроков всего.
Чему я научусь в уроке «Наследование и полиморфизм»?
Изучите объектно-ориентированные принципы, такие как наследование, абстрактные классы и полиморфизм, в Scala. Ты практикуешь Scala for Backend Engineering & Functional Programming с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Scala for Backend Engineering & Functional Programming?
Предыдущий опыт не требуется. Scala for Backend Engineering & Functional Programming на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 2.
Сколько времени занимает урок «Наследование и полиморфизм»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Scala for Backend Engineering & Functional Programming?
Да. Каждый урок Scala for Backend Engineering & Functional Programming включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Классы, объекты и пакеты
- Наследование и полиморфизм