Kotlin 物件:Object 與 Singleton

object 是 Kotlin 中一個非常獨特且強大的關鍵字。簡單來說,它同時完成了兩件事:

  1. 定義一個類別 (Class)
  2. 建立該類別的一個實例 (Instance)

這聽起來可能很抽象,但它主要解決了三個常見的程式設計情境:單例模式靜態成員替代品、以及 匿名內部類別

單例模式 (Singleton Pattern)

為什麼需要單例?

在開發應用程式時,有些物件我們只需要 一個全域唯一的實例,例如:

  • 資料庫連線設定 (DatabaseConfig)
  • 網路請求管理器 (NetworkManager)
  • 系統設定 (AppSettings)

在 Java 中,要實作執行緒安全的 Singleton 很麻煩(需要寫 getInstance, synchronized, double-checked locking...)。 但在 Kotlin,你只需要把 class 改成 object,一切就搞定了。

如何使用

// 定義:使用 object 關鍵字
object DatabaseConfig {
    val url = "jdbc:mysql://localhost:3306/db"
    
    fun connect() {
        println("Connecting to $url...")
    }
}

fun main() {
    // 使用:直接用「類別名稱」存取,不需要 (也不能) new
    DatabaseConfig.connect() 
    println(DatabaseConfig.url)
}
Kotlin 的 Object Declaration 是 執行緒安全 (Thread-safe) 的,且採用 惰性初始化 (Lazy Initialization),也就是第一次被存取時才會真正建立物件。

伴生物件 (Companion Object)

這裡沒有 static 關鍵字!

許多從 Java 轉過來的開發者會問:「Kotlin 的 static 去哪了?」 答案是:Kotlin 沒有 static 關鍵字

Kotlin 認為 static 會破壞物件導向的完整性。取而代之的是,如果你需要「不依賴實例就能呼叫」的方法或屬性(類別層級的成員),你應該使用 Companion Object

如何使用

把它想成是這個類別的一個「隨身伴侶」物件。

class User {
    // 這是「實例」成員:每個 User 都有自己的 name
    var name: String = ""

    // 這是「類別」成員:所有 User 共用一份
    companion object {
        // 全域常數
        const val MAX_AGE = 100
        
        // 工廠方法 (Factory Method)
        fun createDefault(): User {
            return User()
        }
    }
}

fun main() {
    // 就像存取 static 成員一樣
    println(User.MAX_AGE)
    val user = User.createDefault()
}

物件表達式 (Object Expression)

臨時需要的物件

有時候我們只需要一個物件來實作某個介面(例如按鈕點擊監聽器),但不想為此特地去開一個新的 .kt 檔案定義一個 Class。 這時候就可以用 Object Expression,它對應到 Java 的 匿名內部類別 (Anonymous Inner Class)

如何使用

語法是 object : 介面或類別 { ... }

interface ClickListener {
    fun onClick()
}

fun main() {
    // "我需要一個實作 ClickListener 的物件,但我不想幫它取類別名稱"
    val listener = object : ClickListener {
        override fun onClick() {
            println("Button clicked!")
        }
    }
    
    listener.onClick()
}

臨時的資料容器

你甚至可以用它建立一個沒有型別的臨時物件來裝資料:

val tempPoint = object {
    val x = 10
    val y = 20
}
println("${tempPoint.x}, ${tempPoint.y}")

總結

  • Object Declaration (object Name):用來實作 單例模式 (Singleton),全域唯一。
  • Companion Object (companion object):放在 class 內部,用來取代 Java 的 static 重點 (常數、工廠方法)。
  • Object Expression (object : Type):用來建立 匿名物件,通常用於再一次性的介面實作。