연습: 클래스 및 컬렉션

1. 시작하기 전에

이 과정에서는 일반적인 사항, 클래스의 다양한 유형, 컬렉션 및 고차 함수에 관해 배웠습니다. 이제 새로운 이벤트 추적 앱을 개선하는 과정을 통해 배운 내용을 연습해 보세요. 각 단계의 안내는 앱의 현재 상태와 완료해야 하는 작업을 설명합니다.

이러한 문제를 해결하려면 Kotlin 플레이그라운드를 사용하는 것이 좋습니다.

기본 요건

  • Compose 사용 시 알아야 하는 Android 기본사항3단원 과정 1과 그 이전 과정을 완료해야 합니다.
  • 클래스, 객체, 컬렉션, 고차 함수를 비롯한 Kotlin 프로그래밍 언어의 기본사항에 관해 잘 알고 있어야 합니다.

필요한 항목

2. 앱 개요

여러분은 이벤트 추적 앱팀에 최근에 합류한 소프트웨어 엔지니어입니다. 이 앱의 목적은 사용자가 이벤트를 추적할 수 있도록 하는 것입니다. 팀에서 앱의 기능을 빌드하는 데 도움이 되는 작업을 할당해 드립니다.

각 작업이 끝날 때 자신의 솔루션을 제공된 솔루션과 비교해야 합니다. 원하는 기능을 빌드하는 방법은 여러 가지가 있으므로 자신의 코드가 제공된 솔루션 코드와 정확히 일치하지 않더라도 걱정하지 마세요.

동일한 시작점에서 시작할 수 있도록 이전 작업에서 제공한 솔루션 코드를 다음 작업의 시작 코드로 사용합니다.

3. 작업 1

다른 소프트웨어 엔지니어가 이미 앱에 관한 대략적인 작업을 완료했고, 여러분은 세부사항을 구현하도록 작업을 할당받았습니다.

Event 클래스를 구현해야 합니다. 이 클래스는 사용자가 입력한 이벤트의 세부정보를 유지하는 데 사용됩니다. (힌트: 이 클래스는 메서드를 정의하거나 작업을 실행할 필요가 없습니다.)

이 작업을 위해 Event라는 데이터 클래스를 만들어야 합니다.

이 클래스의 인스턴스는 다음을 저장할 수 있어야 합니다.

  • 문자열 형식의 이벤트 제목
  • 문자열 형식의 이벤트 설명 (null일 수 있음)
  • 문자열 형식의 이벤트 시간대. 이벤트가 오전이나 오후에 시작되는지, 또는 저녁에 시작되는지만 추적하면 됩니다.
  • 정수로 된 분 단위의 이벤트 소요 시간

계속하기 전에 코드를 직접 작성해 보세요.

코드를 사용하여 다음 정보로 인스턴스를 만듭니다.

  • 제목: Kotlin 학습
  • 설명: 하루에 15분 이상 Kotlin을 학습합니다.
  • 시간대: 저녁
  • 소요 시간: 15분

객체를 출력하여 다음 출력이 표시되는지 확인합니다.

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

작업을 완료했거나 최선을 다해 시도한 후 다음을 클릭하여 코딩 방법을 확인하세요.

4. 작업 1 솔루션

솔루션은 다음 코드와 비슷해야 합니다.

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

5. 작업 2

프로젝트를 계속 추적하기 위해 관리자는 Codelab에서 데이터 클래스에 제공한 코드를 사용하기로 합니다.

팀원들이 한동안 Event 클래스를 사용한 후 상급 팀원은 시간대에 문자열을 사용하는 것이 이상적이지 않음을 알게 되었습니다.

'Morning'이라는 값을 적용한 개발자도 있고 'morning'을 사용한 개발자도 있고 'MORNING'을 사용한 개발자도 있었습니다.

이로 인해 많은 문제가 발생했습니다.

이번 작업은 일부 코드를 리팩터링하여 이 문제를 해결하는 것입니다. 리팩터링은 기능을 변경하지 않고 코드를 개선하는 과정입니다. 그 예로 로직을 단순화하거나 반복되는 코드를 별도의 함수로 이동하는 것을 들 수 있습니다.

이 문제를 해결하기 위해 제한된 수의 고유한 값 집합을 모델링하는 데 사용할 수 있는 클래스 유형은 무엇일까요?

팀에서는 enum 클래스를 사용하도록 시간대 코드를 변경하려고 합니다. enum 클래스를 사용하면 팀원이 제공된 시간대 값 중 하나를 반드시 선택해야 하므로 이러한 유형의 문제를 피할 수 있습니다.

enum 클래스의 이름은 Daypart로 지정해야 합니다. 이 클래스는 다음과 같은 3가지 값을 포함해야 합니다.

  • MORNING
  • AFTERNOON
  • EVENING

이 enum 클래스는 어떻게 만들 수 있을까요?

Event 클래스가 이를 사용하도록 하려면 어떻게 리팩터링해야 할까요?

계속 진행하기 전에 자신만의 솔루션을 코딩해 보세요.

다음을 클릭하여 코딩 방법을 확인해 보세요.

6. 작업 2 솔루션

enum class Daypart {
    MORNING,
    AFTERNOON,
    EVENING,
}

이제 리팩터링된 Event 데이터 클래스에서 enum 클래스를 사용합니다.

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

7. 작업 3

동료들은 리팩터링된 Daypart를 사용하는 것을 좋아하지만, 또 다른 문제가 있습니다.

다음 코드는 현재 사용자의 이벤트를 생성하고 저장하는 방법을 보여줍니다.

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)

여러 이벤트가 생성되었으며 현재 각 이벤트에는 자체 변수가 필요합니다. 이벤트를 더 많이 만들수록 모두 추적하기가 더 어려워집니다. 이 접근 방식을 사용할 경우 사용자가 예약한 이벤트 수를 파악하기가 얼마나 어려울까요?

이러한 이벤트의 저장소를 더 효과적으로 구성하는 방법을 생각해 보세요.

어떻게 하면 모든 이벤트를 하나의 변수에 저장할 수 있을까요? (참고: 더 많은 이벤트가 추가될 수 있으므로 유연한 방식이어야 합니다.) 변수에 저장된 이벤트 수도 효율적으로 반환할 수 있어야 합니다.

어떤 클래스나 데이터 유형을 사용하는 것이 좋을까요? 더 많은 이벤트를 추가하는 한 가지 방법은 무엇일까요?

이제 이 기능을 구현해 볼 차례입니다. 다음을 클릭하여 솔루션을 확인하기 전에 코드를 작성해 보세요.

8. 작업 3 솔루션

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

9. 작업 4

관리자는 앱이 운영되어 가는 상황에 만족하지만, 사용자가 이벤트 소요 시간에 따라 짧은 이벤트 요약을 볼 수 있어야 한다고 판단합니다. 예: '5개의 짧은 이벤트가 있음'

'짧은' 이벤트는 60분 미만의 이벤트입니다.

이전 작업 솔루션의 events 변수 코드를 사용하여 이러한 결과를 얻으려면 어떻게 해야 할까요?

다음을 클릭하여 솔루션을 계속 진행합니다.

10. 작업 4 솔루션

이를 달성하는 방법에는 여러 가지가 있으며, 여기에서 솔루션으로 제시하는 방법은 다음과 같습니다.

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

11. 작업 5

팀원들은 앱이 운영되어 가는 상황에 만족하지만, 사용자가 모든 이벤트와 시간대의 요약을 볼 수 있기를 원합니다.

출력은 다음과 비슷해야 합니다.

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

이전 단계의 events 변수 코드를 사용하여 이러한 결과를 얻으려면 어떻게 해야 할까요?

다음을 클릭하여 솔루션 코드를 확인하세요.

12. 작업 5 솔루션

다음은 이 Codelab에서 제시하는 솔루션이며, 다른 변형도 허용됩니다.

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

13. 작업 6

현재는 동료가 색인을 사용하여 마지막 항목을 찾고 출력합니다. 사용된 코드는 println("Last event of the day: ${events[events.size - 1].title}")입니다.

관리자는 이 코드를 단순화할 수 있는 함수에 관해 Kotlin 문서를 확인할 것을 제안합니다.

어떤 함수를 찾으셨나요?

이를 사용하여 동일한 결과가 출력되었는지 확인합니다.

다음을 클릭하여 솔루션을 확인하세요.

14. 작업 6 솔루션

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

15. 작업 7

팀에서는 여러분이 디자인한 데이터 클래스를 좋아하지만, 다음과 같이 필요할 때마다 문자열로 된 이벤트 소요 시간의 코드를 작성하는 것이 반복적이라는 것을 알게 되었습니다.

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

클래스에 메서드를 직접 추가하여 이 반복 문제를 수정할 수도 있지만, 다른 팀이 앱에서 이벤트 클래스를 사용하기 시작했으므로 이 방법은 적당하지 않습니다. 클래스가 변경되면 변경사항으로 인해 코드가 중단되는 일이 없도록 모든 코드를 다시 테스트해야 합니다.

데이터 클래스를 직접 변경하지 않고 위의 코드와 동일한 값을 반환하는 확장 속성을 작성하려면 어떻게 해야 할까요?

올바르게 구현되면 다음 코드를 사용하여 이 작업을 시작할 때 표시된 코드와 동일한 메시지를 출력할 수 있습니다.

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

다음을 클릭하여 솔루션을 계속 진행합니다.

16. 작업 7 솔루션

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

17. 추가 연습

Kotlin 언어에 관해 더 연습하려면 JetBrains 아카데미에서 제공하는 Kotlin 핵심 트랙을 확인하세요. 특정 주제로 이동하려면 지식 지도로 이동하여 트랙에서 다루는 주제 목록을 살펴보세요.