Kotlin教學 | 從零開始學Kotlin | Kotlin入門 | CH9: 介面(Interface)

介面

介面像是一個合約,它定義了一個類別應該做什麼,但是卻不明確定義它應該怎麼做到(實現)。
讓不同的類別能以自己的方式實現同一個介面,這種模式又稱作多型(Polymorphism)。
由於介面不一定提供實現,因此介面不能直接產生物件,介面透過類別繼承和實現後產生物件。

介面的使用步驟:

  1. 宣告介面:宣告介面的成員(屬性和函數)。
  2. 實現介面:宣告類別繼承介面,覆蓋介面成員和實現(如果需要的話)。
  3. 使用實現了介面的類別:創造類別的物件以使用介面的成員。

1. 宣告介面

interface InterfaceName {
    // 成員變量(屬性)
    var mutableProperty: Type1
        get() { ... }
        set(value) { ... }

    val immutableProperty: Type2
        get() { ... }

    // 成員函數
    fun FunctionName() {
        // Function body
    }
}

  • interface:使用interface關鍵字定義介面。
  • 成員變量(屬性):必須是抽象屬性自定義訪問器的屬性
    • 抽象屬性:沒有提供初始值。
    • 自定義訪問器的屬性:自定義的 gettersetter 方法,且方法的實現不能存取支持欄位(backing fields)。
  • 成員函數:可以是默認方法抽象方法
    • 默認方法(有具體實現的方法):提供默認的實現,繼承這個介面的類別可以選擇覆蓋這個方法,或繼續使用這個默認實現。
    • 抽象方法(無具體實現的方法):不提供默認的實現,繼承這個介面的類別覆蓋方法和實現。

Example

interface Vehicle {
    val numberOfWheels: Int
    fun drive()
    fun honk() {
        println("Beep, beep!")
    }
}

這個介面包含一個屬性 numberOfWheels 和兩個方法 drive()honk()
honk() 方法提供了默認的實現。

2. 實現介面

現在,我們將創建一個 Car 類別來實現 Vehicle 介面。

在這個 Car 類別中,我們覆蓋了 numberOfWheels 屬性和 drive() 方法。
我們沒有提供 honk() 方法的新實現,所以 Car 類別將繼承 Vehicle 介面中的默認實現。

class Car : Vehicle {
    override val numberOfWheels: Int = 4
    
    override fun drive() {
        println("The car is driving on $numberOfWheels wheels.")
    }
    // `honk` 方法繼承了 `Vehicle` 的默認實現,所以不需要再次實現
}

3. 使用實現了介面的類別

最後,我們將實例化 Car 類別並調用其方法:

這個例子展示了如何創建一個介面,如何讓一個類別實現該介面,以及如何覆蓋介面中的方法或者使用介面提供的默認實現。

fun main() {
    val myCar = Car()
    myCar.drive()   // 輸出: The car is driving on 4 wheels.
    myCar.honk()    // 輸出: Beep, beep!
}

介面繼承

介面可以從其他介面繼承,它可以為其成員提供實現,並聲明新的函數和屬性。
實現此類介面的類別只需要定義缺少的實現。

interface Named {
    val name: String
}

interface Person : Named {
    val firstName: String
    val lastName: String
    override val name: String get() = "$firstName $lastName"
}

class Employee(
    override val firstName: String,
    override val lastName: String,
) : Person

解決覆蓋衝突

當一個類別同時實現多個介面,並且這些介面中存在具有相同的方法時,就會產生覆蓋衝突(overriding conflicts)。
這種情況下,該類別必須明確指定它選擇使用哪個介面中的實現,或者提供一個新的實現來覆蓋這些方法。

interface A {
    fun foo() { print("A") }
    fun bar()
}

interface B {
    fun foo() { print("B") }
    fun bar() { print("bar") }
}

class C : A {
    override fun bar() { print("bar") }
}

class D : A, B {
    override fun foo() {
        super<A>.foo()
        super<B>.foo()
    }

    override fun bar() {
        super<B>.bar()
    }
}
  • 介面 A 和 B 都聲明了 foo()bar() 兩個函數。
    兩個介面都為 foo() 提供了實現,但只有 Bbar() 提供了實現。
  • 類別 C 實現了介面 A,因此它必須覆蓋 bar() 方法,提供具體的實現。
    由於 A 中的 foo() 方法已經有了默認實現,C 可以選擇覆蓋 foo() 或者直接繼承其實現。
  • 類別 D 同時實現了介面 AB
    由於 AB 都提供了 foo() 方法的實現,D 面臨著覆蓋衝突。
    此外,即使 B 提供了 bar() 方法的實現,D 也必須覆蓋 bar(),因為它是從兩個介面繼承而來的方法。
    因此,在 D 類別中,覆蓋 foo() 方法解決來自 AB 的覆蓋衝突,foo() 的實現分別調用 super<A>.foo()super<B>.foo()
    對於 bar() 方法,由於只有 B 提供了實現,D 通過 super<B>.bar() 直接使用了 B 中的實現。

Reference

https://kotlinlang.org/docs/interfaces.html

發佈留言