Kotlin Tutorial(14)列舉型態 << 前情
設計功能比較複雜的應用程式,除了基本的繼承架構外,通常會使用介面(interface)提供更靈活的設計架構。各種平台與框架也會使用介面提供特定的功能,例如Android平台與JavaFX的元件監聽架構(listener),用來執行使用者操作功能的設計。這一章先說明Kotlin介面的宣告、實作與使用。
宣告與實作Kotlin介面
Kotlin使用interface關鍵字宣告介面,可以宣告與類別一樣的屬性與函式,不過介面通常用來宣告沒有初始化的變數,稱為抽象屬性變數(abstract properties),還有沒有實作的函式,稱為抽象函式(abstract function)。下面是宣告Kotlin介面的語法:
interface 介面名稱 [: 介面名稱,...]{
// 一般屬性變數
val | var 變數名稱 [: 型態] = 值
// 抽象屬性變數
val | var 變數名稱 : 型態
// 一般函式
fun 函式名稱(參數名稱 : 參數型態,...) : 回傳型態 { ... }
// 抽象函式
fun 函式名稱(參數名稱 : 參數型態,...) : 回傳型態
}
介面通常用來整合不同的繼承架構,同樣可以使用多型的特性,讓應用程式的設計更加靈活。下面是一個Kotlin介面的範例:
package net.macdidi5.kotlin.tutorial.ch15
// 使用interface宣告介面
interface Greeting01 {
// 宣告沒有實作的抽象函式
fun greet(name: String): String
}
一個宣告好的介面可以讓類別實作,下面是類別實作介面的語法:
class 類別名稱 : 介面名稱,... {
// 覆寫(override)介面的抽象屬性變數與抽象函式
// 其它類別需要的宣告
}
類別在實作介面以後,必須實作介面宣告的抽象函式,否則會發生編譯錯誤。下面是實作與使用介面的範例:
package net.macdidi5.kotlin.tutorial.ch15
...
// 宣告實作Greeting01介面的類別
class Greeting01Impl : Greeting01 {
// 使用override關鍵字
// 覆寫Greeting01介面的greet抽象函式
// 函式的宣告必須和介面的抽象函式一樣
override fun greet(name : String): String {
return "Hello! $name!"
}
}
// 宣告一個接收Greeting01物件參數的函式
fun sayHello(greeting : Greeting01) {
println(greeting.greet("Simon"))
}
fun main(args: Array<String>) {
// 建立實作Greeting01介面的物件
val greeting01 = Greeting01Impl()
// 呼叫函式並傳送Greeting01物件
sayHello(greeting01)
// 顯示: Hello! Simon!
}
包含抽象屬性的介面
Kotlin介面跟類別一樣,可以宣告一般的的屬性變數與函式。除了一般常見的抽象函式外,也可以宣告抽象屬性,讓實作的類別決定屬性的值。下面是一個包含抽象屬性與其它宣告的介面:
package net.macdidi5.kotlin.tutorial.ch15
interface Greeting02 {
// 宣告抽象屬性變數
val name : String
// 宣告一般屬性變數
val upperName : String
get() = name.toUpperCase()
// 宣告抽象函式
fun message(): String
// 宣告一般函式
fun displayName() {
println("Name: $name")
}
// 宣告一般函式
fun displayGreeting() {
println("Hello, $upperName")
}
}
實作包含抽象屬性介面的類別,必須覆寫介面宣告的抽象屬性,其它抽象函式也必須覆寫:
package net.macdidi5.kotlin.tutorial.ch15
// 宣告實作Greeting02介面的類別
class Greeting02Impl : Greeting02 {
// 覆寫Greeting02介面的name抽象屬性
override val name = "Simon"
// 覆寫Greeting02介面的message抽象函式
override fun message(): String {
return "Hello! $name!"
}
}
// 宣告一個接收Greeting02物件參數的函式
fun sayHello02(greeting02 : Greeting02) {
println(greeting02.message())
}
fun main(args: Array<String>) {
// 建立實作Greeting02介面的物件
val greeting0201 = Greeting02Impl()
// 使用Greeting02介面宣告的屬性變數
println("${greeting0201.name}, ${greeting0201.upperName}")
// 顯示: Simon, SIMON
// 呼叫Greeting02介面宣告的一般函式
greeting0201.displayName()
// 顯示: Name: Simon
greeting0201.displayGreeting()
// 顯示: Hello, SIMON
// 呼叫函式並傳送Greeting02物件
sayHello02(greeting0201)
// 顯示: Hello! Simon!
}
介面的繼承
與類別的繼承一樣,介面也可以繼承介面,不過類別只能繼承一個父類別,通常會稱為「單一繼承」,而介面可以繼承多個介面。下面是之前說明過的介面宣告:
package net.macdidi5.kotlin.tutorial.ch15
// 使用interface宣告介面
interface Greeting01 {
// 宣告沒有實作的抽象函式
fun greet(name: String): String
}
為了靈活的設計應用程式架構,你可以讓介面繼承另外一個介面,繼承的效果與類別繼承是類似的,同樣會繼承父介面宣告的抽象與非抽象屬性與函式,
package net.macdidi5.kotlin.tutorial.ch15
// 使用interface宣告介面,指定Greeting01為父介面(super interface)
interface Greeting03 : Greeting01 {
// 宣告沒有實作的抽象函式
fun getGreeting() : String
}
實作上面的介面時,就必須實作所有的抽象屬性與函式:
package net.macdidi5.kotlin.tutorial.ch15
// 宣告實作Greeting02介面的類別
class Greeting03Impl : Greeting03 {
// 覆寫Greeting01介面的greet抽象函式
override fun greet(name : String): String {
return "Hello! $name!"
}
// 覆寫Greeting03介面的getGreeting抽象函式
override fun getGreeting(): String {
return greet("Mary")
}
}
fun main(args: Array<String>) {
// 建立實作Greeting03介面的物件
val greeting0301 = Greeting03Impl()
println(greeting0301.greet("Simon"))
println(greeting0301.getGreeting())
// 顯示:
// Hello! Simon!
// Hello! Mary!
}
使用匿名類別實作介面
上面說明的方式,先宣告一個實作介面的類別,再建立與使用這個類別的物件。不過如果應用程式須要實作介面的類別,只會在特定的地方使用,建議可以使用匿名類別(anynomous clas)的作法,可以讓程式碼更簡單一些。下面是使用匿名類別宣告與實作介面的語法:
val 變數名稱 = object : 介面名稱,... {
// 覆寫(override)介面的抽象屬性變數與抽象函式
// 其它類別需要的宣告
}
以上面說明的應用來說,使用object關鍵字,可以一次完成宣告類別與建立物件的工作:
package net.macdidi5.kotlin.tutorial.ch15
import java.time.LocalDate
import java.time.LocalDateTime
...
// 宣告一個接收Greeting01物件參數的函式
fun sayHello(greeting : Greeting01) {
println(greeting.greet("Simon"))
}
fun main(args: Array<String>) {
...
// 宣告與實作Greeting01介面的物件
val greeting02 = object : Greeting01 {
override fun greet(name : String): String {
return "Hello! $name! ${LocalDate.now()}"
}
}
sayHello(greeting02)
// 顯示: Hello! Simon! 2017-12-19
// 在方法的參數宣告與實作Greeting01介面的物件
sayHello(object : Greeting01 {
override fun greet(name : String): String {
return "Hello! $name! ${LocalDateTime.now()}"
}
})
// 顯示: Hello! Simon! 2017-12-19T11:51:40.792
}
下面是另外一個使用匿名類別實作介面的範例:
package net.macdidi5.kotlin.tutorial.ch15
import java.time.LocalDate
import java.time.LocalDateTime
...
// 宣告一個接收Greeting02物件參數的函式
fun sayHello02(greeting02 : Greeting02) {
println(greeting02.message())
}
fun main(args: Array<String>) {
...
// 宣告與實作Greeting02介面的物件
val greeting0202 = object : Greeting02 {
override val name = "Mary"
override fun message(): String {
return "Hello! $name! ${LocalDate.now()}"
}
}
sayHello02(greeting0202)
// 顯示: Hello! Mary! 2017-12-19
// 在方法的參數宣告與實作Greeting02介面的物件
sayHello02(object : Greeting02 {
override val name = "Mary"
override fun message(): String {
return "Hello! $name! ${LocalDateTime.now()}"
}
})
// 顯示: Hello! Mary! 2017-12-19T11:57:01.340
}
下一步
瞭解Kotlin介面的基本概念以後,在開發Android或Java應用程式的時候,也會經常使用Java介面,接下來準備認識如何使用kotlin程式語言實作Java介面。
相關的檔案都可以在GitHub瀏覽與下載。
http://github.com/macdidi5/Kotlin-Tutorial
後續 >> Kotlin Tutorial(16)介面與實作(下)
|