← Scala EspañolChapter 08 of 13

Herencia

## Objetivos de Aprendizaje - Comprender la herencia de clases - Dominar clases abstractas - Trabajar con traits - Aprender mixins y linearizacion - Override metodos correctamente ## Herencia de Clases ### Extendiendo una Clase ```scala class Animal { def speak(): String = "Some sound" } class Dog extends Animal { override def speak(): String = "Woof!" } class Cat extends Animal { override def speak(): String = "Meow!" } val dog: Animal = new Dog() println(dog.speak()) // Woof! ``` ### Modificador Override El modificador `override` es requerido al sobrescribir metodos concretos: ```scala class Animal { def speak(): String = "..." } class Dog extends Animal { override def speak(): String = "Woof!" // override requerido } ``` ### Miembros Final Previene sobrescritura con `final`: ```scala class Animal { final def speak(): String = "..." } class Dog extends Animal { // No se puede sobrescribir speak() } ``` ## Clases Abstractas ### Definiendo Clases Abstractas ```scala abstract class Shape { def area(): Double // Abstracto - sin implementacion def perimeter(): Double // Abstracto def color(): String = "White" // Concreto - con implementacion } ``` ### Extendiendo Clases Abstractas ```scala class Circle(val radius: Double) extends Shape { def area(): Double = Math.PI * radius * radius def perimeter(): Double = 2 * Math.PI * radius override def color(): String = "Red" } class Rectangle(val width: Double, val height: Double) extends Shape { def area(): Double = width * height def perimeter(): Double = 2 * (width + height) } ``` ## Traits Los traits definen contratos y pueden proporcionar implementaciones por defecto: ```scala trait Printable { def print(): Unit = println(toString()) } trait Serializable { def serialize(): String } ``` ### Mezclando Traits ```scala class Document(val title: String) extends Printable with Serializable { override def toString: String = s"Document($title)" def serialize(): String = title } val doc = new Document("My Doc") doc.print() ``` ### Traits con Metodos Abstractos ```scala trait Iterator[T] { def hasNext: Boolean def next(): T } class IntIterator(start: Int, end: Int) extends Iterator[Int] { private var current = start def hasNext: Boolean = current < end def next(): Int = { val result = current current += 1 result } } val iter = new IntIterator(1, 5) while (iter.hasNext) { println(iter.next()) } ``` ## Multiples Traits (Mixins) ### Linearizacion Cuando una clase extiende multiples traits, Scala usa linearizacion para resolver llamadas a metodos: ```scala trait A { def greet(): String = "A" } trait B extends A { override def greet(): String = "B" } trait C extends A { override def greet(): String = "C" } class D extends A with B with C { // Linearizacion: D -> C -> B -> A -> AnyRef -> Any // greet() resuelve al implementacion de C } val d = new D() d.greet() // "C" (el mas a la derecha gana) ``` ### Composicion de Mixins ```scala trait Logging { def log(msg: String): Unit = println(s"[LOG] $msg") } trait Timestamping extends Logging { abstract override def log(msg: String): Unit = { super.log(s"${java.time.Instant.now()}: $msg") } } class Service { def process(): Unit = log("Processing") } object Main extends App { val service = new Service with Logging val timestampedService = new Service with Timestamping service.log("Hello") // [LOG] Hello timestampedService.log("Hello") // [LOG] 2024-01-01T12:00:00Z: Hello } ``` ## Orden de Constructores Los constructores se ejecutan de padre a hijo: ```scala class Animal { println("Animal constructor") def speak(): String = "..." } class Dog extends Animal { println("Dog constructor") override def speak(): String = "Woof!" } new Dog() // Salida: // Animal constructor // Dog constructor ``` ## Clases Selladas Las clases selladas restringen quais clases pueden extenderlas: ```scala sealed abstract class Result case class Success(value: Int) extends Result case class Failure(message: String) extends Result case object Pending extends Result def describe(result: Result): String = result match { case Success(v) => s"Success: $v" case Failure(msg) => s"Failed: $msg" case Pending => "Pending" } // No se pueden agregar nuevas subclases fuera de este archivo ``` ## Herencia de Case Class ```scala // Herencia con case classes sealed trait Tree case class Node(left: Tree, right: Tree) extends Tree case class Leaf(value: Int) extends Tree def sum(tree: Tree): Int = tree match { case Node(l, r) => sum(l) + sum(r) case Leaf(v) => v } ``` ## Seguridad de Objetos ```scala class Base { def method(x: Int): String = x.toString } class Derived extends Base { override def method(x: Int): String = s"($x)" } val b: Base = new Derived() b.method(5) // Llama a Derived.method ``` ## Rol de AnyRef y Any ```text Any ├── AnyVal (Int, Double, Boolean, etc.) └── AnyRef ├── java.lang.Object (en JVM) ├── Clases de usuario └── scala.Null ``` ## Mejores Practicas 1. **Favorecer composicion sobre herencia** cuando sea posible 2. **Usar traits/classes selladas** para emparejamiento de patrones exhaustivo 3. **Usar clases abstractas** cuando necesites parametros de constructor 4. **Usar traits** para reutilizacion de codigo entre clases no relacionadas 5. **Mantener linearizacion simple** - evitar jerarquias de traits profundas ## Resumen - Las clases extienden otras clases con `extends` - El modificador `override` es requerido para sobrescribir metodos - Las clases abstractas pueden tener miembros abstractos y concretos - Los traits proporcionan interfaz e implementacion por defecto - La linearizacion determina el orden de resolucion de metodos de traits - Las clases selladas restringen extension al mismo archivo - Usa case classes para estructuras de datos inmutables - Los constructores se ejecutan de padre a hijo

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →