domingo, 25 de junio de 2017

Un resumen de Scala for the Impatient, parte 23


Sobrescribir campos

Se puede sobrescribir val (o un método sin parámetros) con una declaración val con el mismo nombre. La clase tiene privados los atributos y públicos los getters y setters por lo tanto se sobrescribirán estos métodos.

Por ejemplo:

class Person(val name: String) {
     override def toString = getClass.getName + "[name=" + name + "]"
}

class SecretAgent(codename: String) extends Person(codename) {
     override val name = "secret" // Don’t want to reveal name . . .
     override val toString = "secret" // . . . or class name
}

Este ejemplo muestra el mecanismo, pero es bastante artificial. Un caso más común es sobrescribir un def de una clase abstracta, veamos un ejemplo :

abstract class Person { // See Section 8.8 for abstract classes
     def id: Int // Each person has an ID that is computed in some way
     ...
}

class Student(override val id: Int) extends Person
// A student ID is simply provided in the constructor

Note las siguientes restricciones:
  • Un def solo puede ser sobrescrito por un def
  • Un val solo puede ser sobrescrito por otro val o un def sin parámetros
  • Un var solo puede ser sobrescrito por un var abstracto


Veamos un cuadro que describe la sobrecarga:



Con val
Con def
Con var
Sobrescribir val
La subclase tiene un campo privado (con el mismo nombre que el campo de la superclase: está bien).
Getter reemplaza al getter de superclase.
Error
Error
Sobrescribir def
La subclase tiene un campo privado.
Getter anula el método de superclase.
Como java.
Una var puede anular un par getter / setter.
Anular solo el getter produce un error.
Sobrescribir var
Error
Error
Sólo si la superclase var es abstracta

Subclases anónimas.

Como en java, se pueden implementar interfaces o extender clases abstractas implementando los métodos a continuación del llamado de dicha clase o interfaz, es más fácil explicar esto con un ejemplo:

val alien = new Person("Fred") {
     def greeting = "Greetings, Earthling! My name is Fred."
}

Técnicamente esto creo una persona con el método “greeting” implementado con el texto: "Greetings, Earthling! My name is Fred." El tipo es Person{def greeting: String}. Se puede utilizar este tipo como parámetro de la siguiente forma:

def meet(p: Person{def greeting: String}) {
     println(p.name + " says: " + p.greeting)
}

Clases Abstractas.

Como en java, podemos definir una clase abstracta con la palabra “abstract” y esta clase no se podrá instanciar. Normalmente esto es usado de la siguiente manera porque hay uno o más métodos que no podemos definir, es decir que son abstractos.

abstract class Person(val name: String) {
     def id: Int // No method body—this is an abstract method
}

Una subclase de Person va a estar obligada a implementar el método id o ser abstracta. A diferencia de java no es necesario utilizar la palabra abstract para los métodos, simplemente debemos omitir el cuerpo de la función.

Una subclase concreta esta obligada a sobre escribir este método:

class Employee(name: String) extends Person(name) {
     def id = name.hashCode // override keyword not required
}