Introducción

En este tema, exploraremos dos características poderosas de Kotlin: las clases de datos y las clases selladas. Estas características permiten escribir código más limpio y seguro, y son fundamentales para aprovechar al máximo el lenguaje Kotlin.

Clases de Datos

¿Qué es una Clase de Datos?

Una clase de datos en Kotlin es una clase que se utiliza principalmente para almacenar datos. Kotlin proporciona una forma concisa de declarar estas clases, y automáticamente genera métodos útiles como equals(), hashCode(), toString(), copy(), y destructuring declarations.

Declaración de una Clase de Datos

Para declarar una clase de datos, utilizamos la palabra clave data antes de la declaración de la clase.

data class Persona(val nombre: String, val edad: Int)

Métodos Generados Automáticamente

  1. toString(): Proporciona una representación de cadena de la clase.
  2. equals() y hashCode(): Permiten comparar objetos y utilizarlos en colecciones que dependen de estos métodos.
  3. copy(): Crea una copia del objeto, permitiendo modificar algunas propiedades.
  4. Destructuring Declarations: Permite descomponer un objeto en sus componentes.

Ejemplo Práctico

fun main() {
    val persona1 = Persona("Juan", 25)
    val persona2 = Persona("Juan", 25)

    // Uso de toString()
    println(persona1) // Output: Persona(nombre=Juan, edad=25)

    // Uso de equals()
    println(persona1 == persona2) // Output: true

    // Uso de copy()
    val persona3 = persona1.copy(edad = 30)
    println(persona3) // Output: Persona(nombre=Juan, edad=30)

    // Uso de destructuring declarations
    val (nombre, edad) = persona1
    println("Nombre: $nombre, Edad: $edad") // Output: Nombre: Juan, Edad: 25
}

Ejercicio Práctico

Ejercicio:

Declara una clase de datos llamada Libro con las propiedades titulo (String), autor (String) y anioPublicacion (Int). Crea una instancia de Libro y utiliza los métodos generados automáticamente.

Solución:

data class Libro(val titulo: String, val autor: String, val anioPublicacion: Int)

fun main() {
    val libro1 = Libro("1984", "George Orwell", 1949)
    val libro2 = Libro("1984", "George Orwell", 1949)

    // Uso de toString()
    println(libro1) // Output: Libro(titulo=1984, autor=George Orwell, anioPublicacion=1949)

    // Uso de equals()
    println(libro1 == libro2) // Output: true

    // Uso de copy()
    val libro3 = libro1.copy(anioPublicacion = 2021)
    println(libro3) // Output: Libro(titulo=1984, autor=George Orwell, anioPublicacion=2021)

    // Uso de destructuring declarations
    val (titulo, autor, anio) = libro1
    println("Título: $titulo, Autor: $autor, Año: $anio") // Output: Título: 1984, Autor: George Orwell, Año: 1949
}

Clases Selladas

¿Qué es una Clase Sellada?

Una clase sellada es una clase que restringe la jerarquía de clases. Esto significa que todas las subclases de una clase sellada deben ser declaradas en el mismo archivo. Las clases selladas son útiles para representar tipos limitados y garantizar que todas las posibles subclases sean conocidas en tiempo de compilación.

Declaración de una Clase Sellada

Para declarar una clase sellada, utilizamos la palabra clave sealed antes de la declaración de la clase.

sealed class Resultado
data class Exito(val data: String) : Resultado()
data class Error(val mensaje: String) : Resultado()

Uso de Clases Selladas

Las clases selladas son especialmente útiles en combinaciones con when expressions, ya que el compilador puede verificar que todos los casos posibles están cubiertos.

Ejemplo Práctico

sealed class Resultado
data class Exito(val data: String) : Resultado()
data class Error(val mensaje: String) : Resultado()

fun manejarResultado(resultado: Resultado) {
    when (resultado) {
        is Exito -> println("Éxito: ${resultado.data}")
        is Error -> println("Error: ${resultado.mensaje}")
    }
}

fun main() {
    val resultado1: Resultado = Exito("Datos cargados correctamente")
    val resultado2: Resultado = Error("Error al cargar los datos")

    manejarResultado(resultado1) // Output: Éxito: Datos cargados correctamente
    manejarResultado(resultado2) // Output: Error: Error al cargar los datos
}

Ejercicio Práctico

Ejercicio:

Declara una clase sellada llamada Operacion con dos subclases: Suma y Resta. Cada subclase debe tener dos propiedades a y b de tipo Int. Crea una función que tome una instancia de Operacion y devuelva el resultado de la operación.

Solución:

sealed class Operacion
data class Suma(val a: Int, val b: Int) : Operacion()
data class Resta(val a: Int, val b: Int) : Operacion()

fun calcular(operacion: Operacion): Int {
    return when (operacion) {
        is Suma -> operacion.a + operacion.b
        is Resta -> operacion.a - operacion.b
    }
}

fun main() {
    val suma = Suma(10, 5)
    val resta = Resta(10, 5)

    println("Resultado de la suma: ${calcular(suma)}") // Output: Resultado de la suma: 15
    println("Resultado de la resta: ${calcular(resta)}") // Output: Resultado de la resta: 5
}

Conclusión

En esta sección, hemos aprendido sobre las clases de datos y las clases selladas en Kotlin. Las clases de datos nos permiten manejar datos de manera eficiente y concisa, mientras que las clases selladas nos ayudan a restringir la jerarquía de clases y garantizar que todas las posibles subclases sean conocidas en tiempo de compilación. Estos conceptos son fundamentales para escribir código Kotlin limpio, seguro y eficiente.

En el próximo tema, exploraremos las declaraciones de objetos y los objetos compañeros, que nos permitirán entender mejor cómo Kotlin maneja los objetos singleton y las funciones estáticas.

© Copyright 2024. Todos los derechos reservados