0Pricing
Scala for Backend Engineering & Functional Programming · Урок

Наследование и полиморфизм

Изучите объектно-ориентированные принципы, такие как наследование, абстрактные классы и полиморфизм, в 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 — локальная установка не требуется.

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

  1. Классы, объекты и пакеты
  2. Наследование и полиморфизм
← Назад к Scala for Backend Engineering & Functional Programming