Práctica: Clases y colecciones

1. Antes de comenzar

En esta ruta de aprendizaje, aprendiste sobre aspectos genéricos, diferentes tipos de clases, colecciones y funciones de orden superior. Para practicar lo que aprendiste, ayudarás a tu equipo a mejorar su nueva app de seguimiento de eventos. En las instrucciones para cada paso, se describe el estado actual de la app y la tarea que se espera que completes.

Para resolver estos ejercicios, te recomendamos que uses Kotlin Playground.

Requisitos previos

  • Completar la Ruta de aprendizaje 1 de la unidad 3 del curso Aspectos básicos de Android con Compose y las rutas de aprendizaje anteriores
  • Conocer los conceptos básicos del lenguaje de programación Kotlin (incluidas las clases, los objetos, las colecciones y las funciones de orden superior)

Requisitos

2. Descripción general de la app

Eres el ingeniero de software más nuevo del equipo que desarrolla la app de seguimiento de eventos. El objetivo de esta app es permitir que los usuarios realicen un seguimiento de sus eventos. Tu equipo te asignará tareas para ayudar a compilar la funcionalidad de la app.

Al final de cada tarea, deberás comparar tu solución con la que te brindamos. Existen diferentes maneras de lograr la funcionalidad deseada, por lo que no debes preocuparte si el código no coincide exactamente con el código de solución que se proporcionó.

Usa dicho código de solución en la tarea anterior como código de inicio para la siguiente tarea a fin de comenzar en un punto de partida común.

3. Tarea 1

Otro ingeniero de software ya realizó algunos trabajos importantes para la app, y tú debes implementar los detalles.

Debes implementar la clase Event. Esta clase se utiliza para conservar los detalles del evento que ingresó el usuario. (Sugerencia: Esta clase no necesita definir ningún método ni realizar ninguna acción).

Para esta tarea, debes crear una clase de datos llamada Event.

Una instancia de esta clase debería poder almacenar lo siguiente:

  • El título del evento como una string
  • La descripción del evento como una string (puede ser nula)
  • La segmentación del día del evento como una cadena (solo debemos realizar un seguimiento si el evento comienza a la mañana, a la tarde o a la noche)
  • La duración del evento en minutos como un número entero

Antes de continuar, intenta escribir el código por tu cuenta.

Con tu código, crea una instancia que contenga la siguiente información:

  • Título: Estudiar Kotlin
  • Descripción: Comprometerse a estudiar Kotlin al menos 15 minutos al día.
  • Segmentación del día: Noche
  • Duración: 15 minutos

Intenta imprimir tu objeto para verificar que obtienes el siguiente resultado:

Event(title=Study Kotlin, description=Commit to studying Kotlin at least 15 minutes per day., daypart=Evening, durationInMinutes=15)

Una vez que completes la tarea o hagas tu mejor intento, haz clic en Siguiente para ver el modo en que se codificó.

4. Solución de la tarea 1

La solución debería ser similar al siguiente código:

data class Event(
    val title: String,
    val description: String? = null,
    val daypart: String,
    val durationInMinutes: Int,
)

5. Tarea 2

A fin de mantener el rumbo del proyecto, tu gerente decide usar el código que nosotros proporcionamos para la clase de datos.

Después de que los miembros de tu equipo usaran la clase Event durante un tiempo, el compañero de equipo sénior se dio cuenta de que usar una string para la franja horaria no es lo ideal.

Algunos desarrolladores almacenaron el valor "Mañana", otros usaron "mañana", y otros usaron "MAÑANA".

Esto causó muchos problemas.

Tu tarea es solucionar este problema con una refactorización. La refactorización es el proceso de mejorar el código sin cambiar su funcionalidad. Algunos ejemplos son simplificar la lógica o mover el código repetido a funciones separadas.

¿Qué tipo de clase se puede usar para modelar un conjunto limitado de valores distintos a fin de corregir este problema?

Tu equipo desea que cambies el código de la franja horaria para usar una clase enum. Cuando usas este tipo de clase, tus compañeros de equipo se ven obligados a elegir uno de los valores de franja horaria proporcionados, lo que evita estos tipos de problemas.

La clase enum debería llamarse Daypart. Debería tener tres valores:

  • MORNING
  • AFTERNOON
  • EVENING

¿Cómo crearías esta clase enum?

¿Cómo refactorizarías tu clase Event para usarla?

Intenta codificar tu solución ahora antes de continuar.

Haz clic en Siguiente para ver el modo en que se codificó.

6. Solución de la tarea 2

enum class Daypart {
    MORNING,
    AFTERNOON,
    EVENING,
}

La clase de datos Event refactorizada ahora usa la clase enum:

data class Event(
    val title: String,
    val description: String? = null,
    val daypart: Daypart,
    val durationInMinutes: Int,
)

7. Tarea 3

Tus colegas disfrutan el uso del elemento Daypart refactorizado, pero experimentan otros problemas.

El siguiente código es la forma en la que actualmente crean y almacenan los eventos del usuario.

val event1 = Event(title = "Wake up", description = "Time to get up", daypart = Daypart.MORNING, durationInMinutes = 0)
val event2 = Event(title = "Eat breakfast", daypart = Daypart.MORNING, durationInMinutes = 15)
val event3 = Event(title = "Learn about Kotlin", daypart = Daypart.AFTERNOON, durationInMinutes = 30)
val event4 = Event(title = "Practice Compose", daypart = Daypart.AFTERNOON, durationInMinutes = 60)
val event5 = Event(title = "Watch latest DevBytes video", daypart = Daypart.AFTERNOON, durationInMinutes = 10)
val event6 = Event(title = "Check out latest Android Jetpack library", daypart = Daypart.EVENING, durationInMinutes = 45)

Crearon muchos eventos y cada uno de ellos requiere su propia variable. A medida que se crean más eventos, se hace más difícil hacer un seguimiento de todos. Con este enfoque, ¿qué tan difícil sería determinar cuántos eventos programó el usuario?

¿Cuál es la mejor forma de organizar el almacenamiento de estos eventos?

¿Cómo se pueden almacenar todos los eventos en una variable? (Nota: Debe ser flexible, ya que se pueden agregar más eventos. También debe mostrar de manera eficaz el recuento de la cantidad de eventos almacenados en la variable).

¿Qué clase o tipo de datos usarías? ¿Cuál de las siguientes opciones es una forma de agregar más eventos?

Ahora, es tu turno de implementar esta función. Intenta escribir el código antes de hacer clic en Siguiente para ver nuestra solución.

8. Solución de la tarea 3

val events = mutableListOf<Event>(event1, event2, event3, event4, event5, event6)

9. Tarea 4

Al administrador le gusta cómo está quedando la app, pero decide que el usuario debería poder ver un resumen de sus eventos cortos en función de la duración estos. Por ejemplo, "Tienes 5 eventos cortos".

Un evento "corto" dura menos de 60 minutos.

Si usas el código de variable events de la solución de la tarea anterior, ¿cómo lograrías este resultado?

Haz clic en Siguiente para continuar con nuestra solución.

10. Solución de la tarea 4

Hay varias formas de hacerlo, y decidimos lo siguiente:

val shortEvents = events.filter { it.durationInMinutes < 60 }
println("You have ${shortEvents.size} short events.")

11. Tarea 5

A tus compañeros de equipo les gusta cómo está quedando la app, pero quieren que los usuarios puedan ver un resumen de todos los eventos y sus franjas horarias.

El resultado debería ser similar al siguiente:

Morning: 3 events
Afternoon: 4 events
Evening: 2 events

Si usas el código de variable events del paso anterior, ¿cómo lograrías este resultado?

Haz clic en Siguiente para ver el código de la solución.

12. Solución de la tarea 5

La siguiente es nuestra solución, pero también se aceptan otras variaciones.

val groupedEvents = events.groupBy { it.daypart }
groupedEvents.forEach { (daypart, events) ->
    println("$daypart: ${events.size} events")
}

13. Tarea 6

En este momento, tu colega encuentra y muestra el último elemento con el índice. El código utilizado es println("Last event of the day: ${events[events.size - 1].title}").

Tu administrador te sugiere consultar la documentación de Kotlin para encontrar una función que pueda simplificar este código.

¿Qué función encontraste?

Úsala para confirmar que obtienes los mismos resultados para mostrar.

Haz clic en Siguiente para ver la solución.

14. Solución de la tarea 6

println("Last event of the day: ${events.last().title}")

15. Tarea 7

A tu equipo le gusta la clase de datos que diseñaste, pero le resulta repetitivo escribir código cada vez que necesitan la duración de un evento como string:

val durationOfEvent = if (events[0].durationInMinutes < 60) {
        "short"
    } else {
        "long"
    }
println("Duration of first event of the day: $durationOfEvent")

Aunque puedes corregir esta repetición si agregas un método directamente a la clase, no es conveniente, ya que otros equipos comenzaron a usar el evento en sus apps. Si se cambia la clase, deberán volver a probar todo el código para asegurarse de que no haya fallas a causa del cambio.

Sin cambiar directamente la clase de datos, ¿cómo puedes escribir una propiedad de extensión que muestre los mismos valores que el código anterior?

Cuando se implementa correctamente, podrás usar el siguiente código, que mostrará el mismo mensaje que el código que se muestra al comienzo de esta tarea.

println("Duration of first event of the day: ${events[0].durationOfEvent}")

Haz clic en Siguiente para ver a la solución.

16. Solución de la tarea 7

val Event.durationOfEvent: String
    get() = if (this.durationInMinutes < 60) {
        "short"
    } else {
        "long"
    }

17. Práctica adicional

Si quieres obtener más información sobre el lenguaje Kotlin, consulta la segmentación principal de Kotlin de JetBrains Academy. Para ir a un tema específico, ve al mapa del conocimiento y consulta la lista de temas del segmento.