Trong bài viết này, cafedev chia sẻ cho bạn về các interface và cách triển khai nó trong Kotlin với sự trợ giúp của các ví dụ.

Các interface trong Kotlin tương tự như các interface trong Java 8. Chúng có thể chứa các định nghĩa về các hàm trừu tượng cũng như triển khai các hàm không trừu tượng. Tuy nhiên, chúng không thể chứa bất kỳ trạng thái nào.

Điều này có nghĩa là, interface có thể có thuộc tính nhưng nó cần phải trừu tượng hoặc phải triển khai bộ truy cập (accessor).

Bài đọc được đề xuất: Class trừu tượng trong Kotlin

Các class  trừu tượng trong Kotlin cũng tương tự như interface nhưng có một điểm khác biệt quan trọng. Các thuộc tính của một class  trừu tượng không nhất thiết phải là trừu tượng hoặc phải triển khai bộ truy cập (accessor).

1. Làm thế nào để xác định một interface?

Từ khóa interface được sử dụng để xác định interface trong Kotlin. Ví dụ,

interface MyInterface {

    var test: String   // abstract property

    fun foo()          // abstract method
    fun hello() = "Hello there" // method with default implementation
}

Ở đây,

  • Một interface có tên là MyInterface đã được tạo ra.
  • interface này có một thuộc tính trừu tượng là  test và một hàm trừu tượng là hàm foo().
  • interface này cũng có một hàm không trừu tượng là hàm hello().

2. Làm thế nào để triển khai interface?

Dưới đây là cách mà một class hoặc một đối tượng có thể triển khai interface:

interface MyInterface {

    val test: Int   // abstract property

    fun foo() : String   // abstract method (returns String)
    fun hello() {   // method with default implementation
        // body (optional)
    }
}

class InterfaceImp : MyInterface {

    override val test: Int = 25
    override fun foo() = "Lol"

    // other code
}

Ở đây, một class  có tên là InterfaceImp đã triển khai interface có tên là MyInterface.

Class này ghi đè các thành viên trừu tượng (thuộc tính test và hàm foo()) của interface đó.

3. Ví dụ: interface hoạt động như thế nào?

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

interface MyInterface {

    val test: Int

    fun foo() : String

    fun hello() {
        println("Hello there, pal!")
    }
}

class InterfaceImp : MyInterface {

    override val test: Int = 25
    override fun foo() = "Lol"

}

fun main(args: Array<String>) {
    val obj = InterfaceImp()

    println("test = ${obj.test}")
    print("Calling hello(): ")

    obj.hello()

    print("Calling and printing foo(): ")
    println(obj.foo())
}

Bây giờ khi bạn chạy chương trình, kết quả sẽ là:

test = 25
Calling hello(): Hello there, pal!
Calling and printing foo(): Lol

Như đã đề cập ở trên, một interface cũng có thể có một thuộc tính triển khai bộ truy cập. Ví dụ,

interface MyInterface {

    // property with implementation
    val prop: Int
        get() = 23
}

class InterfaceImp : MyInterface {
    // class body
}

fun main(args: Array<String>) {
    val obj = InterfaceImp()

    println(obj.prop)
}

Bây giờ khi bạn chạy chương trình, kết quả sẽ là:

23

Ở đây, prop không phải là trừu tượng. Tuy nhiên, nó hợp lệ bên trong interface vì nó triển khai bộ truy cập (accessor).

Tuy nhiên, bạn không thể viết code là val prop: Int = 23 bên trong interface được.

4. Triển khai hai hoặc nhiều interface trong một class 

Kotlin không cho phép đa kế thừa thực sự . Tuy nhiên, chúng ta có thể triển khai hai hoặc nhiều interface trong một class  duy nhất. Ví dụ,

interface A {

    fun callMe() {
        println("From interface A")
    }
}

interface B  {
    fun callMeToo() {
        println("From interface B")
    }
}

// implements two interfaces A and B
class Child: A, B

fun main(args: Array<String>) {
    val obj = Child()

    obj.callMe()
    obj.callMeToo()
}

Bây giờ khi bạn chạy chương trình, kết quả sẽ là:

From interface A
From interface B

5. Giải quyết xung đột ghi đè (nhiều interface)

Giả sử, hai interface (A và B) có một hàm không trừu tượng có cùng tên (giả sử là hàm callMe() chẳng hạn). Bạn đã triển khai hai interface này trong một class  (giả sử đó là class có tên là C). Bây giờ, nếu bạn gọi hàm callMe() bằng cách sử dụng đối tượng của class C, trình biên dịch sẽ báo lỗi. Ví dụ,

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

interface A {

    fun callMe() {
        println("From interface A")
    }
}

interface B  {
    fun callMe() {
        println("From interface B")
    }
}

class Child: A, B 

fun main(args: Array<String>) {
    val obj = Child()

    obj.callMe()
}

Sau đây là lỗi được báo về:

Error:(14, 1) Kotlin: Class 'C' must override public open fun callMe(): Unit defined in A because it inherits multiple interface methods of it

Để giải quyết vấn đề này, bạn cần cung cấp cách triển khai của riêng mình. Dưới đây là cách thực hiện:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

interface A {

    fun callMe() {
        println("From interface A")
    }
}

interface B  {
    fun callMe() {
        println("From interface B")
    }
}

class C: A, B {
    override fun callMe() {
        super<A>.callMe()
        super<B>.callMe()
    }
}

fun main(args: Array<String>) {
    val obj = C()

    obj.callMe()
}

Bây giờ khi bạn chạy chương trình, kết quả sẽ là:

From interface A
From interface B

Ở đây, triển khai rõ ràng của hàm callMe() được cung cấp trong class C.

class C: A, B {
    override fun callMe() {
        super<A>.callMe()
        super<B>.callMe()
    }
}

Câu lệnh (đoạn code) gọi hàm callMe() của class A. Tương tự, (đoạn code) gọi hàm callMe() của class  B.

Full series tự học Kotlin từ cơ bản tới nâng cao.

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!