0Pricing
Scala for Backend Engineering & Functional Programming · Lección

Herencia y polimorfismo

Explore principios de la programación orientada a objetos, como la herencia, las clases abstractas y el polimorfismo en Scala.

Herencia y polimorfismo es una lección gratuita de Scala for Backend Engineering & Functional Programming en CoddyKit. Esta es la lección 2 de 2. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Scala for Backend Engineering & Functional Programming, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Scala for Backend Engineering & Functional Programming incluye 2 lecciones en total.

¿Qué es la herencia?

La herencia es un concepto fundamental de la Programación Orientada a Objetos (POO) que permite que una clase nueva herede propiedades y comportamientos (métodos) de una clase existente.

Considérela como una relación entre «padre e hijo». La clase «hija» (subclase) reutiliza el código de la clase «padre» (superclase), lo que ahorra tiempo y garantiza la coherencia.

  • Promueve la reutilización del código.
  • Establece una relación «es-un» (por ejemplo, un Dog es un Animal).
  • Ayuda a organizar el código en una jerarquía.

Su primera clase base

Definamos una clase Animal sencilla. Esta será nuestra clase base, también conocida como superclase o clase padre. Tiene un comportamiento básico: hablar.

Ejecute el código para ver en acción a nuestro animal genérico.

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()
  }
}

Extender con `extends`

Ahora creemos un animal más específico, un Dog. Un Dog es un Animal, por lo que puede heredar de la clase Animal mediante la palabra clave extends.

También podemos sobrescribir el método speak para asignarle a Dog su propio sonido distintivo. Observe la palabra clave 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!
  }
}

El poder de `override`

La palabra clave override es fundamental en Scala por varias razones:

  • Claridad: indica explícitamente a otros desarrolladores que este método o campo reemplaza a uno de la superclase.
  • Seguridad: el compilador comprueba que realmente esté sobrescribiendo un miembro existente. Si comete un error tipográfico o cambia el método de la superclase, el compilador le avisará.
  • Intención: deja clara su intención de especializar o cambiar el comportamiento heredado.

Use siempre override al redefinir miembros heredados.

Polimorfismo: muchas formas

El polimorfismo significa «muchas formas». En la POO, permite tratar objetos de distintas clases como objetos de una superclase común.

Esto significa que puede tener una variable de tipo Animal que contenga un objeto Dog, un objeto Cat o cualquier otra subclase de Animal. Al llamar a un método sobre esa variable, se ejecuta el método correcto para el tipo real del objeto.

  • Permite crear código flexible y extensible.
  • Permite usar una única interfaz para distintos tipos de datos.
  • Se consigue mediante la sobrescritura de métodos.

El polimorfismo en la práctica

Veamos el polimorfismo en acción. Crearemos una clase Cat similar a Dog. Después, podremos incluir distintos tipos de animales en una lista de su supertipo común, Animal, y llamar a su método speak.

Observe que cada animal habla de una manera propia, aunque todos se traten como tipos Animal en la lista.

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())
  }
}

Introducción a las clases abstractas

A veces, necesita una clase base que defina una interfaz común, pero que no proporcione una implementación completa para algunos de sus miembros. Ahí es donde entran en juego las clases abstractas.

Una clase abstracta:

  • No se puede instanciar directamente (no puede crear un objeto de una clase abstracta).
  • Puede contener métodos abstractos (métodos sin implementación) y métodos concretos (métodos con implementación).
  • Sirve como plano que sus subclases deben completar.

Construcción de planos abstractos

Definamos una abstract class Shape. Toda figura tiene un área, pero la fórmula para calcularla varía según la figura concreta (círculo, rectángulo, etc.).

Por eso, declaramos area como un método abstracto. Observe que no tiene cuerpo (no contiene = { ... }). Las subclases serán responsables de proporcionar su implementación.

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.")
  }
}

Implementaciones concretas

Ahora creemos subclases concretas como Circle y Rectangle, que extiendan nuestra abstract class Shape. Estas subclases deben proporcionar una implementación para el método abstracto area.

También heredan el método concreto describe() de 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()
  }
}

Comprobación de herencia y polimorfismo

¿Cuáles de las siguientes afirmaciones sobre la herencia y el polimorfismo en Scala son VERDADERAS?

Repaso: herencia y polimorfismo

¡Excelente trabajo! En esta lección, hemos explorado conceptos fundamentales de la POO en Scala:

  • Herencia: cómo las subclases reutilizan código y definen una relación «es-un» con las superclases mediante extends.
  • Palabra clave override: es esencial para redefinir explícitamente métodos y campos heredados, garantizando la seguridad de tipos y la claridad.
  • Polimorfismo: la capacidad de tratar objetos de distintas subclases como objetos de una superclase común, lo que permite crear código flexible y extensible.
  • Clases abstractas: planos que no se pueden instanciar directamente y que se usan para definir interfaces comunes y miembros abstractos que las subclases deben implementar.

Estos conceptos son fundamentales para crear aplicaciones Scala bien estructuradas y fáciles de mantener.

Preguntas frecuentes

¿La lección «Herencia y polimorfismo» es gratis?

Sí — el texto completo de «Herencia y polimorfismo» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Scala for Backend Engineering & Functional Programming, actualiza a CoddyKit PRO. El curso de Scala for Backend Engineering & Functional Programming incluye 2 lecciones en total.

¿Qué aprenderé en «Herencia y polimorfismo»?

Explore principios de la programación orientada a objetos, como la herencia, las clases abstractas y el polimorfismo en Scala. Practicas Scala for Backend Engineering & Functional Programming con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Scala for Backend Engineering & Functional Programming?

No se requiere experiencia previa. Scala for Backend Engineering & Functional Programming en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 2.

¿Cuánto tiempo toma la lección «Herencia y polimorfismo»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Scala for Backend Engineering & Functional Programming?

Sí. Cada lección de Scala for Backend Engineering & Functional Programming incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Clases, objetos y paquetes
  2. Herencia y polimorfismo
← Volver a Scala for Backend Engineering & Functional Programming