Bỏ qua để đến nội dung

🛡️ Visibility Modifiers

🎯 Mục tiêu: Kiểm soát quyền truy cập vào code của bạn bằng các từ khóa: public, private, protected, internal.


Kotlin có 4 visibility modifiers:

  1. public (mặc định): Truy cập từ bất cứ đâu.
  2. private: Chỉ truy cập trong phạm vi khai báo (file hoặc class).
  3. protected: Truy cập trong class và subclasses (không có cho top-level).
  4. internal: Truy cập trong cùng Module.

Đối với biến, hàm, class khai báo trực tiếp trong file:

Example.kt
package foo
fun baz() {} // public: dùng ở đâu cũng được
private fun foo() {} // private: chỉ dùng được trong file Example.kt
internal val bar = 5 // internal: chỉ dùng được trong module này

Đối với member trong Class:

open class Outer {
private val a = 1 // Chỉ trong Outer
protected open val b = 2 // Trong Outer + Subclasses
internal val c = 3 // Trong cùng Module
val d = 4 // Public (mặc định)
protected class Nested {
public val e: Int = 5
}
}
class Subclass : Outer() {
// a không thấy
// b, c, d thấy được
// Nested thấy được
override val b = 5 // Vẫn giữ protected
}
class Unrelated(o: Outer) {
// o.a, o.b không thấy
// o.c, o.d thấy được (nếu cùng module)
}

Để thay đổi visibility của constructor, bạn phải thêm từ khóa constructor:

class C private constructor(a: Int) { ... }

Class này không thể được khởi tạo từ bên ngoài!


Modifier internal giới hạn trong Module. Một module trong Kotlin có thể là:

  • Một IntelliJ IDEA module.
  • Một Maven project.
  • Một Gradle source set (VD: main, test).

Điều này cực kỳ hữu ích để tạo các thư viện: bạn có thể có các hàm tiện ích public cho nội bộ thư viện dùng (internal), nhưng người dùng thư viện không thấy được, giữ API sạch sẽ.


Bài tập 1: Thiết kế API

Tạo một class Library chỉ cho phép truy cập qua các hàm public, giấu kín implementation details.

class Library internal constructor() { // Chỉ tạo được trong module
private val books = mutableListOf<String>()
fun addBook(title: String) {
books.add(title)
log("Added $title")
}
private fun log(msg: String) {
println("[Lib]: $msg")
}
}
// ❌ Không thể tạo Library() ở module khác

  • Hiểu public là mặc định
  • Dùng private để đóng gói dữ liệu
  • Dùng internal cho các thành phần nội bộ module
  • Phân biệt protected của Kotlin và Java