Kotlin Tutorial(13)多型的特性與應用 << 前情
設計應用程式的時候,除了基本的繼承架構外,通常也需要一些資料結構,例如產品分類、會員等級,或是項目的顏色。這類的應用通常是少數幾個固定的資料,使用變數或類別設計的話,會是比較麻煩的。接下來要討論Kotlin提供的列舉型態,它是一種特殊的類別,非常適合用來設計這類資料結構。
認識列舉類別
一個記事資料App,可以讓使用者依照自己的需求,設定每一個記事項目的顏色,例如把重要的項目設定為紅色,這樣的設計可以讓應用程式提供更清楚的記事資料畫面:
應用程式提供幾種可以設定的記事資料顏色,以上面的畫面來說有六種顏色,使用者為記事項目選擇顏色以後,應用程式就需要把顏色保存在記事資料。像這類資料結構可以在應用程式宣告像這樣的列舉類別:
package net.macdidi5.kotlin.tutorial.ch14
// 宣告顏色列舉型態,包含六個顏色成員
enum class Colors01 {
// 列出所有成員的名稱,有六種顏色的名稱,每一個名稱之間使用逗號隔開
LIGHTGREY, BLUE, PURPLE,
GREEN, ORANGE, RED
}
上面宣告的列舉類別Colors01,是一個特殊的類別,宣告與用法都跟一般的類別不一樣。列舉類別型態的變數,只能指定在類別中宣告好的成員名稱:
// 宣告紅、藍、綠三個顏色變數
val c01: Colors01 = Colors01.RED
val c02: Colors01 = Colors01.BLUE
val c03: Colors01 = Colors01.GREEN
println("$c01, $c02, $c03")
// 顯示: RED, BLUE, GREEN
Kotlin會自動為列舉類別加入一些函式,例如把字串轉換為列舉類別型態,可以呼叫Kotlin自動加入的valueOf函式:
// 把紅、藍、綠顏色名稱字串轉換為列舉型態變數
val c04: Colors01 = Colors01.valueOf("RED")
val c05: Colors01 = Colors01.valueOf("BLUE")
val c06: Colors01 = Colors01.valueOf("GREEN")
println("$c04, $c05, $c06")
// 顯示: RED, BLUE, GREEN
Kotlin自動加入的函式還有values,它可以傳回所有宣告在這個列舉類別型態裡面的成員,型態是列舉類別陣列。每一個列舉類別成員有Kotlin自動加入的ordinal與name兩個屬性,分別是成員的索引編號(Int)和名稱(String):
// 取得包含列舉型態所有成員的陣列
val cs: Array<Colors01> = Colors01.values()
for (c in cs) {
println("${c.ordinal}: ${c.name}")
}
// 顯示:
// 0: LIGHTGREY
// 1: BLUE
// 2: PURPLE
// 3: GREEN
// 4: ORANGE
// 5: RED
判斷列舉型態變數
宣告好顏色列舉類別以後,應用程式為了設定記事項目的顏色,需要另外宣告一個判斷顏色代碼的函式:
enum class Colors01 {
LIGHTGREY, BLUE, PURPLE,
GREEN, ORANGE, RED
}
// 傳回參數的顏色代碼
fun getColorCode(color: Colors01) =
// 判斷顏色並傳回對應的代碼
when (color) {
Colors01.LIGHTGREY -> 0XD3D3D3
Colors01.BLUE -> 0X33B5E5
Colors01.PURPLE -> 0XAA66CC
Colors01.GREEN -> 0X99CC00
Colors01.ORANGE -> 0XFFBB33
Colors01.RED -> 0XFF4444
}
應用程式需要設定記事顏色的時候,可以呼叫上面的函式取得對應的顏色代碼:
val c01: Colors01 = Colors01.RED
val c02: Colors01 = Colors01.BLUE
val c03: Colors01 = Colors01.GREEN
// toString(16)可以把整數轉換為16進位字串
println("$c01: ${getColorCode(c01)}, ${getColorCode(c01).toString(16)}")
println("$c01: ${getColorCode(c02)}, ${getColorCode(c02).toString(16)}")
println("$c01: ${getColorCode(c03)}, ${getColorCode(c03).toString(16)}")
// 顯示:
// RED: 16729156, ff4444
// RED: 3388901, 33b5e5
// RED: 10079232, 99cc00
為列舉類別成員加入對應的資料
如果應用程式需要的列舉類別,每一個成員都一個固定的對應資料,例如上面說明的顏色代碼。這類需求可以使用下面的語法,把對應的資料整合在列舉類別裡面:
enum class 名稱(val 參數名稱: 參數型態) {
成員名稱(對應的值),...
}
下面的列舉類別額外加入接收顏色代碼參數的主要建構式,再把每一個顏色對應的代碼設定在成員後面:
package net.macdidi5.kotlin.tutorial.ch14
// 如果列舉型態需要包含每一個成員對應的資料,
// 在宣告的時候加入成員對應資料的參數
enum class Colors02(val value: Int) {
// 在每一個成員名稱後的左右刮號裡面填入對應的資料
LIGHTGREY(0XD3D3D3), BLUE(0X33B5E5), PURPLE(0XAA66CC),
GREEN(0X99CC00), ORANGE(0XFFBB33), RED(0XFF4444)
}
整合成員對應資料的列舉類別,除了一般的使用方式外,可以直接使用主要建構式的參數名稱,取得每一個成員對應的資料:
val c01 = Colors02.RED
val c02 = Colors02.BLUE
val c03 = Colors02.GREEN
// 列舉型態變數多了建構式參數指定的屬性
println("$c01: ${c01.value}")
println("$c02: ${c02.value}")
println("$c03: ${c03.value}")
// 顯示:
// RED: 16729156
// BLUE: 3388901
// GREEN: 10079232
雖然為列舉類別加入主要建構式,不過它不可以跟一般類別一樣,呼叫建構式建立物件:
// 編譯錯誤,不可以呼叫建構式
// val c = Colors02(0XFF4444)
Kotlin自動加入的valueOf函式,可以把字串轉換為列舉類別型態。如果應用程式需要把成員對應的資料,轉換為列舉類別型態,就需要自己撰寫函式執行判斷與轉換的工作:
enum class Colors02(val value: Int) {
LIGHTGREY(0XD3D3D3), BLUE(0X33B5E5), PURPLE(0XAA66CC),
GREEN(0X99CC00), ORANGE(0XFFBB33), RED(0XFF4444);
}
// 接收顏色代碼參數,傳回對應的列舉型態變數
fun parseColor(value: Int): Colors02 {
// 設定預設的顏色為LIGHTGREY
var result: Colors02 = Colors02.LIGHTGREY
for (c in Colors02.values()) {
// 判斷顏色代碼
if (value == c.value) {
result = c
break
}
}
return result
}
下面的程式片段示範轉換顏色代碼的作法:
// 呼叫函式把顏色代碼轉換為列舉型態變數
val c04 = parseColor(0XFF4444)
val c05 = parseColor(0X33B5E5)
val c06 = parseColor(0X000000)
println("\n$c04, $c05, $c06")
// 顯示: RED, BLUE, LIGHTGREY
宣告額外的函式
如果列舉型態變數需要執行一些額外的處理,例如把整數的顏色代碼轉換為十六進位,你可以把這類的函式整合在列舉類別裡面:
package net.macdidi5.kotlin.tutorial.ch14
enum class Colors03(val value: Int) {
LIGHTGREY(0XD3D3D3), BLUE(0X33B5E5), PURPLE(0XAA66CC),
GREEN(0X99CC00), ORANGE(0XFFBB33), RED(0XFF4444);
// 為列舉型態加入函式,傳回顏色代碼十六進位的字串
fun colorCode() = "0X${value.toString(16).toUpperCase()}"
}
為列舉類別加入函式以後,就可以使用列舉型態變數呼叫這些函式:
val c01 = Colors03.RED
val c02 = Colors03.BLUE
val c03 = Colors03.GREEN
// 可以使用列舉型態變數呼叫函式
println("$c01: ${c01.colorCode()}")
println("$c02: ${c02.colorCode()}")
println("$c03: ${c03.colorCode()}")
// 顯示:
// RED: 0XFF4444
// BLUE: 0X33B5E5
// GREEN: 0X99CC00
使用列舉型態
設計好需要的顏色列舉類別後,就可以在記事類別中使用它來儲存顏色,而且可以使用整合的顏色代碼,在畫面顯示記事項目的顏色:
package net.macdidi5.kotlin.tutorial.ch14
// 為記事類別加入顏色屬性,預設值為Colors02.LIGHTGREY
class Item(val id: Long, var title: String, var content: String,
var color: Colors02 = Colors02.LIGHTGREY) {
fun getDetails() =
"Item01(id=$id, title=$title, content=$content), color=${color}"
}
fun main(args: Array<String>) {
val item01 = Item(1, "Hello", "World", Colors02.RED)
println(item01.getDetails())
// 顯示: Item(id=1, title=Hello, content=World), color=RED
val item02 = Item(2, "Hi", "Kotlin", Colors02.BLUE)
println("id: ${item02.id}, color.value: ${item02.color.value}")
// 顯示: id: 2, color.value: 3388901
val item03 = Item(3, "Greeting", "Good morning")
println("id: ${item03.id}, color: ${item03.color}, color.value: ${item03.color.value}")
// 顯示: iid: 3, color: LIGHTGREY, color.value: 13882323
}
下一步
API或Android的應用程式設計架構,經常使用的介面(Interface)是接下來討論的主題,包含設計與使用interface以後,為了讓程式碼比較清楚一些,也會使用巢狀類別與匿名類別的設計。
相關的檔案都可以在GitHub瀏覽與下載。
http://github.com/macdidi5/Kotlin-Tutorial
後續 >> Kotlin Tutorial(15)介面與實作(上)
|