En Scala, las clases y los objetos son fundamentales para la programación orientada a objetos. Las clases son plantillas para crear objetos, mientras que los objetos son instancias únicas de una clase. Los objetos pueden contener métodos, variables y otros tipos de definiciones.
// Definición de una clase en Scala
class Persona(var nombre: String, var edad: Int) {
// Método dentro de la clase Persona
def saludar(): Unit = {
println(s"Hola, mi nombre es $nombre y tengo $edad años.")
}
}
// Creación de objetos (instancias) de la clase Persona
val persona1 = new Persona("Juan", 30)
val persona2 = new Persona("María", 25)
// Llamada al método saludar() de cada objeto
persona1.saludar()
persona2.saludar()
Definición de Clase (class
):
class
. En el ejemplo, Persona
es una clase que tiene dos variables miembro (nombre
y edad
) y un método (saludar()
).Variables Miembro (var
):
nombre
y edad
en este caso) son accesibles y modificables desde fuera de la clase.Método (def
):
saludar()
dentro de la clase Persona
imprime un mensaje utilizando las variables miembro nombre
y edad
.Creación de Objetos:
new
, seguida del nombre de la clase y los parámetros necesarios para inicializar las variables miembro.Llamada a Métodos:
persona1.saludar()
y persona2.saludar()
llaman al método saludar()
para cada objeto Persona
.En Scala, los constructores son métodos especiales utilizados para inicializar objetos de una clase. Pueden ser primarios (definidos junto con la declaración de la clase) o auxiliares (definidos dentro de la misma clase). Los miembros de clase son variables y métodos que pertenecen a cada instancia de la clase y pueden ser públicos, privados o protegidos.
// Definición de una clase con constructor primario
class Persona(var nombre: String, var edad: Int) {
// Variable miembro privada
private var direccion: String = ""
// Método público para establecer la dirección
def setDireccion(nuevaDireccion: String): Unit = {
direccion = nuevaDireccion
}
// Método público para obtener la dirección
def getDireccion(): String = {
direccion
}
// Método auxiliar (segundo constructor)
def this(nombre: String) {
this(nombre, 0) // Llama al constructor primario
}
}
// Creación de objetos (instancias) de la clase Persona
val persona1 = new Persona("Juan", 30)
val persona2 = new Persona("María")
// Acceso a variables miembro y métodos de clase
persona1.setDireccion("Calle Principal, 123")
println(s"${persona1.nombre} vive en ${persona1.getDireccion()}")
println(s"${persona2.nombre} tiene ${persona2.edad} años.")
Constructor Primario:
class Persona(var nombre: String, var edad: Int)
en este caso). Permite inicializar las variables miembro nombre
y edad
al crear un objeto Persona
.Variables Miembro:
nombre
y edad
son variables miembro públicas de la clase Persona
, accesibles desde fuera de la clase.Variable Miembro Privada:
direccion
es una variable miembro privada de la clase Persona
. Se accede y modifica a través de métodos públicos (setDireccion
y getDireccion
).Método Auxiliar:
def this(nombre: String)
es un método auxiliar dentro de la clase Persona
. Permite crear objetos Persona
sin especificar la edad, llamando al constructor primario con valores predeterminados (0
para edad
).Creación de Objetos:
persona1
y persona2
) se crean usando los constructores definidos. persona1
se inicializa con nombre y edad, mientras que persona2
usa el constructor auxiliar solo con nombre.Acceso a Métodos y Variables Miembro:
nombre
, edad
, direccion
) y cómo llamar métodos (setDireccion
, getDireccion
) en objetos Persona
.En Scala, la herencia permite a una clase (subclase o clase derivada) heredar atributos y métodos de otra clase (superclase o clase base). El polimorfismo permite tratar objetos de distintas clases de manera uniforme a través de una interfaz común.
// Definición de la clase base (superclase)
class Animal(var nombre: String) {
// Método de la clase base
def hacerSonido(): Unit = {
println("Haciendo sonido genérico...")
}
}
// Definición de una subclase que hereda de Animal
class Perro(nombre: String) extends Animal(nombre) {
// Método sobreescrito de la clase base
override def hacerSonido(): Unit = {
println("Guau guau!")
}
// Método adicional de la subclase
def perseguirCola(): Unit = {
println("Persiguiendo la cola...")
}
}
// Función para utilizar polimorfismo
def hacerSonidoAnimal(animal: Animal): Unit = {
animal.hacerSonido()
}
// Creación de objetos y uso de polimorfismo
val animalGenerico = new Animal("Animal")
val miPerro = new Perro("Firulais")
hacerSonidoAnimal(animalGenerico) // Llama al método de la superclase
hacerSonidoAnimal(miPerro) // Llama al método sobreescrito de la subclase
// Acceso a métodos específicos de la subclase
miPerro.perseguirCola()
Herencia:
extends
. class Perro(nombre: String) extends Animal(nombre)
indica que Perro
es una subclase de Animal
, heredando todos los métodos y atributos de la clase base.Método Sobrescrito (override
):
hacerSonido()
es un método de la clase base Animal
, que es sobreescrito en la subclase Perro
para proporcionar un comportamiento específico para los perros ("Guau guau!"
).Polimorfismo:
hacerSonidoAnimal(animal: Animal): Unit
es una función que utiliza polimorfismo. Puede recibir tanto objetos de la clase base (Animal
) como de sus subclases (Perro
). Dependiendo del tipo de objeto pasado, se ejecutará el método correspondiente (hacerSonido()
de Animal
o Perro
).Acceso a Métodos Específicos de la Subclase:
hacerSonidoAnimal
trata a todos los animales de manera uniforme, se puede acceder a métodos específicos de la subclase (perseguirCola()
en Perro
) cuando se tiene una referencia específica al objeto (miPerro
).En Scala, los traits son como interfaces en otros lenguajes de programación, pero pueden contener implementaciones de métodos. Los mixins son clases que mezclan (o combinan) comportamientos de varios traits para reutilizar código en múltiples clases sin herencia múltiple.
// Definición de un trait con métodos abstractos y concretos
trait Cantante {
// Método abstracto
def cantar(): Unit
// Método concreto
def presentarse(): Unit = {
println("Hola, soy un cantante.")
}
}
// Definición de otro trait
trait Bailarin {
// Método abstracto
def bailar(): Unit
// Método concreto
def moverse(): Unit = {
println("Moviendo el cuerpo.")
}
}
// Clase que mezcla (o combina) los traits Cantante y Bailarin
class Artista extends Cantante with Bailarin {
// Implementación del método abstracto de Cantante
def cantar(): Unit = {
println("La la la...")
}
// Implementación del método abstracto de Bailarin
def bailar(): Unit = {
println("Bailando salsa.")
}
}
// Creación de un objeto de la clase Artista
val artista = new Artista
// Llamada a métodos proporcionados por los traits
artista.presentarse()
artista.cantar()
artista.moverse()
artista.bailar()
Traits en Scala:
Cantante
y Bailarin
son traits que definen métodos abstractos (cantar()
y bailar()
) y métodos concretos (presentarse()
y moverse()
).Mixins:
Artista
es una clase que mezcla los traits Cantante
y Bailarin
usando la palabra clave with
. Esto permite que Artista
herede y combine comportamientos de múltiples traits sin herencia múltiple directa.Implementación de Métodos Abstractos:
Artista
, se deben implementar todos los métodos abstractos definidos en los traits (cantar()
y bailar()
).Llamadas a Métodos:
presentarse()
, cantar()
, moverse()
y bailar()
) a través de un objeto Artista
.En Scala, las case classes son clases diseñadas específicamente para almacenar datos inmutables. Son ideales para modelar datos simples y no mutables. El pattern matching es una característica poderosa que permite concordar (match) patrones de datos y ejecutar acciones basadas en esos patrones de forma concisa y expresiva.
// Definición de una case class
case class Persona(nombre: String, edad: Int)
// Función que utiliza pattern matching
def verificarEdad(persona: Persona): String = {
persona match {
case Persona(n, e) if e < 18 => s"$n es menor de edad."
case Persona(n, e) if e >= 18 && e < 65 => s"$n es adulto."
case Persona(n, e) => s"$n es adulto mayor."
}
}
// Creación de objetos (instancias) de la case class Persona
val persona1 = Persona("Juan", 25)
val persona2 = Persona("María", 10)
val persona3 = Persona("Pedro", 70)
// Aplicación del pattern matching a cada objeto
val mensaje1 = verificarEdad(persona1)
val mensaje2 = verificarEdad(persona2)
val mensaje3 = verificarEdad(persona3)
// Impresión de los resultados
println(mensaje1)
println(mensaje2)
println(mensaje3)
Case Classes en Scala:
case class
. Automáticamente proporcionan métodos para la creación de objetos, comparación estructural y acceso a sus campos.Pattern Matching:
verificarEdad
es una función que utiliza pattern matching sobre el argumento persona
. Permite concordar patrones basados en la estructura y valores de la case class Persona
. Los patrones case Persona(n, e) if ...
permiten concordar diferentes casos basados en la edad de la persona (e
).Creación de Objetos y Aplicación del Pattern Matching:
Persona
y se aplica la función verificarEdad
a cada uno de ellos. Dependiendo de la edad de cada persona, se devuelve un mensaje correspondiente.Impresión de Resultados: