Menu
CoddyTech

Khai báo giao diện

Thuộc phần Lập trình hướng đối tượng trong hành trình Kotlin của Coddy. Bài học 22 trên 57.

Một giao diện (interface) liệt kê những gì một kiểu dữ liệu có thể làm mà không nói cách thực hiện. Giao diện khai báo các phương thức và thuộc tính mà mọi lớp triển khai giao diện đều phải cung cấp. Một lớp triển khai giao diện bằng dấu hai chấm, giống như với lớp cha, nhưng không có dấu ngoặc đơn vì giao diện không có hàm khởi tạo:

interface Drawable {
    fun draw(): String
}
class Circle(val radius: Int) : Drawable {
    override fun draw() = "circle with radius $radius"
}
class Line(val length: Int) : Drawable {
    override fun draw() = "-".repeat(length)
}

Bên trong main:

println(Circle(3).draw())
println(Line(5).draw())

Đầu ra:

circle with radius 3
-----

Một giao diện cũng có thể khai báo thuộc tính. Lớp cung cấp các thuộc tính đó dưới dạng thuộc tính hàm khởi tạo, thuộc tính được lưu trữ hoặc getter; bản thân giao diện không lưu trữ gì:

interface Vehicle {
    val wheels: Int
    val label: String
}
class Car(override val label: String) : Vehicle {
    override val wheels = 4
}
class Bike : Vehicle {
    override val wheels = 2
    override val label: String
        get() = "bike on $wheels wheels"
}

Bên trong main:

println("${Car("taxi").label}: ${Car("taxi").wheels}")
println(Bike().label)

Đầu ra:

taxi: 4
bike on 2 wheels

Phải triển khai mọi thành viên mà giao diện khai báo, mỗi thành viên đều cần có override, nếu không lớp sẽ không biên dịch được. Không thể khởi tạo một giao diện:

interface Speaker {
    fun speak(): String
    val volume: Int
}
// class Mute : Speaker { override fun speak() = "" }   // lỗi: chưa triển khai volume
// class Loud : Speaker() { ... }                      // lỗi: interface không có hàm khởi tạo
// val s = Speaker()                                   // lỗi: không thể tạo interface

Cả interface lẫn lớp trừu tượng đều khai báo các thành viên không có phần thân. Interface không có hàm khởi tạo và không lưu trạng thái, còn một lớp có thể triển khai nhiều interface nhưng chỉ kế thừa một lớp. Dùng interface cho một khả năng mà các lớp không liên quan cùng có, chẳng hạn như Drawable hoặc Comparable, và dùng lớp trừu tượng làm lớp cơ sở chung có trạng thái.

interface Drawable { fun draw(): String }                   // một khả năng
abstract class Shape(val name: String) { abstract fun area(): Double }   // một lớp cơ sở có trạng thái
class Square(val s: Double) : Shape("square"), Drawable {  // một lớp, nhiều giao diện
    override fun area() = s * s
    override fun draw() = "[]"
}
challenge icon

Thử thách

Dễ

Khai báo các thành viên của giao diện Shape: thuộc tính chỉ đọc name và các phương thức area(), perimeter(), cả hai đều trả về Double. Hãy để Rectangle(width, height) (tên rectangle) và Circle(radius) (tên circle, sử dụng Math.PI) triển khai các thành viên này. Sau đó hoàn thành describe(shape), hàm này trả về rectangle: area 12.00, perimeter 14.00 với hai chữ số thập phân, chỉ sử dụng các thành viên của Shape.

Code được cung cấp đọc các dòng r,3,4 hoặc c,2, tạo hình tương ứng và in ra describe(shape).

Code của bạn nằm trong các tệp Shape.kt, Rectangle.kt, Circle.kt và Functions.kt. Main.kt chứa code đầu vào/đầu ra được cung cấp và bạn không thể chỉnh sửa tệp này.

Tự làm thử

fun main() {
    // Đoạn code đầu vào/đầu ra đã cung cấp: giữ nguyên
    val input = generateSequence(::readLine).toList()
    for (line in input) {
        val p = line.split(",").map { it.trim() }
        val shape: Shape = if (p[0] == "r") Rectangle(p[1].toDouble(), p[2].toDouble()) else Circle(p[1].toDouble())
        println(describe(shape))
    }
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Playground Kotlin