Introducción

En Scala, los objetos compañeros (companion objects) son una característica poderosa que permite definir métodos y valores que están estrechamente relacionados con una clase, pero que no requieren una instancia de la clase para ser utilizados. Los objetos compañeros se definen utilizando la palabra clave object y deben tener el mismo nombre que la clase a la que acompañan. Esta relación especial permite que el objeto y la clase accedan a los miembros privados entre sí.

Conceptos Clave

  • Objeto Compañero: Un objeto que comparte el mismo nombre que una clase y se define en el mismo archivo fuente.
  • Métodos de Fábrica: Métodos en el objeto compañero que crean instancias de la clase.
  • Acceso a Miembros Privados: Los objetos compañeros y las clases pueden acceder a los miembros privados entre sí.

Definición de un Objeto Compañero

Para definir un objeto compañero, simplemente se utiliza la palabra clave object seguida del nombre del objeto, que debe coincidir con el nombre de la clase. Aquí hay un ejemplo básico:

class Persona(val nombre: String, val edad: Int) {
  // Miembros de la clase
  private def mostrarInfo(): String = s"Nombre: $nombre, Edad: $edad"
}

object Persona {
  // Método de fábrica
  def apply(nombre: String, edad: Int): Persona = new Persona(nombre, edad)

  // Método para crear una Persona a partir de una cadena
  def fromString(info: String): Persona = {
    val partes = info.split(",")
    new Persona(partes(0), partes(1).toInt)
  }
}

En este ejemplo:

  • La clase Persona tiene un constructor que toma dos parámetros: nombre y edad.
  • El objeto Persona define un método apply que actúa como un método de fábrica para crear instancias de Persona.
  • También define un método fromString que crea una instancia de Persona a partir de una cadena.

Uso de Objetos Compañeros

Los objetos compañeros se utilizan para definir métodos y valores que están relacionados con la clase, pero que no dependen de una instancia específica. Aquí hay algunos ejemplos de cómo se pueden utilizar:

Métodos de Fábrica

Los métodos de fábrica son métodos en el objeto compañero que crean instancias de la clase. Esto es útil cuando se necesita lógica adicional para crear instancias.

val persona1 = Persona("Juan", 30)
val persona2 = Persona.fromString("Ana,25")

Acceso a Miembros Privados

Los objetos compañeros y las clases pueden acceder a los miembros privados entre sí. Esto permite encapsular la lógica de manera efectiva.

class CuentaBancaria(private var saldo: Double) {
  def depositar(cantidad: Double): Unit = {
    saldo += cantidad
  }

  def retirar(cantidad: Double): Unit = {
    if (cantidad <= saldo) saldo -= cantidad
    else throw new IllegalArgumentException("Fondos insuficientes")
  }
}

object CuentaBancaria {
  def crearCuentaInicial(saldoInicial: Double): CuentaBancaria = {
    new CuentaBancaria(saldoInicial)
  }
}

En este ejemplo, el objeto CuentaBancaria puede acceder al miembro privado saldo de la clase CuentaBancaria.

Ejercicio Práctico

Ejercicio 1: Definir un Objeto Compañero

Define una clase Libro con los siguientes atributos: titulo (String) y autor (String). Luego, define un objeto compañero que incluya un método de fábrica apply y un método fromCSV que cree una instancia de Libro a partir de una cadena CSV.

class Libro(val titulo: String, val autor: String)

object Libro {
  def apply(titulo: String, autor: String): Libro = new Libro(titulo, autor)

  def fromCSV(csv: String): Libro = {
    val partes = csv.split(",")
    new Libro(partes(0), partes(1))
  }
}

Solución

val libro1 = Libro("1984", "George Orwell")
val libro2 = Libro.fromCSV("Brave New World,Aldous Huxley")

println(s"Libro 1: ${libro1.titulo} por ${libro1.autor}")
println(s"Libro 2: ${libro2.titulo} por ${libro2.autor}")

Ejercicio 2: Acceso a Miembros Privados

Modifica la clase Libro para que tenga un miembro privado precio (Double) y define un método en el objeto compañero que permita actualizar el precio de un libro.

class Libro(val titulo: String, val autor: String, private var precio: Double) {
  def mostrarInfo(): String = s"Titulo: $titulo, Autor: $autor, Precio: $$precio"
}

object Libro {
  def apply(titulo: String, autor: String, precio: Double): Libro = new Libro(titulo, autor, precio)

  def fromCSV(csv: String): Libro = {
    val partes = csv.split(",")
    new Libro(partes(0), partes(1), partes(2).toDouble)
  }

  def actualizarPrecio(libro: Libro, nuevoPrecio: Double): Unit = {
    libro.precio = nuevoPrecio
  }
}

Solución

val libro3 = Libro("El Hobbit", "J.R.R. Tolkien", 15.99)
println(libro3.mostrarInfo())

Libro.actualizarPrecio(libro3, 12.99)
println(libro3.mostrarInfo())

Conclusión

Los objetos compañeros en Scala son una herramienta poderosa para definir métodos y valores que están estrechamente relacionados con una clase, pero que no requieren una instancia de la clase para ser utilizados. Permiten la creación de métodos de fábrica, el acceso a miembros privados y la encapsulación de lógica relacionada con la clase. Al dominar los objetos compañeros, puedes escribir código más limpio y organizado en Scala.

En el próximo tema, exploraremos los objetos singleton, que son otra característica importante de Scala para definir objetos únicos en tu aplicación.

© Copyright 2024. Todos los derechos reservados