練習:類別與集合

1. 事前準備

在這個課程中,您已瞭解一般內容、不同類型的類別、集合和高階函式。善用所學的內容,您將可以協助團隊改善全新的事件追蹤應用程式。每個步驟的操作說明描述了應用程式目前的狀態,以及您應該要完成的任務。

建議使用 Kotlin Playground 來解決這些練習的問題。

必要條件

  • 完成「Android Compose 基本概念」課程的「單元 3 課程 1」,以及準備課程。
  • 熟悉 Kotlin 程式設計語言的基本概念,包括類別、物件、集合和高階函式。

軟硬體需求

2. 應用程式總覽

您是事件追蹤應用程式團隊中最新的軟體工程師。這款應用程式的目的在於讓使用者可以追蹤自己的事件。您的團隊會為您指派任務,協助您建構應用程式的功能。

每項任務結束時,請比較您的解決方案與我們提供的解決方案。達到想要功能的方法有很多種,因此,如果您的程式碼與提供的解決方案程式碼不完全相同,請不用擔心。

使用上一項任務中提供的解決方案程式碼,做為下一個任務的起始程式碼,以便從相同的起點著手。

3. 任務 1

其他軟體工程師已經完成應用程式部分概略的工作,而您則負責實作相關細節。

您必須實作 Event 類別。這個類別可用來保存使用者輸入的事件詳細資料。(提示:這個類別無須定義任何方法或執行任何動作)。

這項任務需要建立一個名為 Event 的資料類別。

這個類別的執行個體應要可以儲存:

  • 以字串的形式儲存事件標題
  • 以字串的形式儲存事件說明 (可以是空值)。
  • 以字串的形式儲存事件時段。我們只需追蹤事件是在早上、下午還是晚上發生。
  • 以分鐘 (整數) 為單位儲存事件時間長度

在繼續往下之前,請試著自行撰寫程式碼。

使用程式碼,利用以下資訊建立執行個體:

  • 標題:學習 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

為了保持專案進度,您的主管決定使用我們提供的資料類別程式碼。

您的團隊成員在使用 Event 類別一段時間後,資深團隊成員發現以字串的方式使用時段並不理想。

有些開發人員儲存的值是「Morning」,有些則使用「morning」,而其他則使用「MORNING」。

這種情況造成很多問題。

您的任務是透過執行重構來修正這個問題。重構意指在功能維持不變的情況下,改善程式碼的過程。有些是簡化邏輯,或是將重複的程式碼移至別的函式。

哪種類別可用來模擬一組有限的值,以協助修正這個問題?

您的團隊想要您修改時段的程式碼,改為使用列舉類別。一旦使用列舉類別,您的小組成員就必須強制選擇其中一種提供的時段值,以避免發生這類問題。

列舉類別應命名為 Daypart。其中應有三個值:

  • MORNING
  • AFTERNOON
  • EVENING

您要如何建立這個列舉類別?

您要如何重構才能使用 Event 類別?

建議您現在編寫解決方案的程式,再繼續往下。

點選「下一步」即可查看我們如何編寫程式碼。

6. 任務 2 解決方案

enum class Daypart {
    MORNING,
    AFTERNOON,
    EVENING,
}

重構的 Event 資料類別現在使用了列舉類別:

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 解決方案

以下是我們提供的解決方案,但也可以採取其他做法。

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 Academy 的 Kotlin 核心概念課程。如要跳到特定主題,請前往知識地圖,瀏覽課程所涵蓋主題的清單。