[譯]Kotlin 中的單例模式

若是我想定義單例模式,那麼它應該是這樣的:java

單例是一種軟件設計模式,它保證一個類只有一個實例,而且該類提供對該實例的全局訪問控制。git

Java 中,一般這樣寫:github

public class Singleton {
    
    private static Singleton instance;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
複製代碼

可是上面的代碼在多線程場景下是有缺陷的。若是兩個線程同時獲取實例,則可能會建立兩個實例。因此對於上面的代碼咱們須要改造。設計模式

class Singleton {

    private static Singleton instance = null;

    private Singleton() {
    }

    private synchronized static void createInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
    }

    public static Singleton getInstance() {
        if (instance == null) createInstance();
        return instance;
    }
}
複製代碼

經過 synchronized 關鍵字能夠確保在建立 instance 時沒有線程衝突,只建立一個實例。安全

Kotlin 中能夠這樣實現:多線程

class Singleton private constructor() {
    
    private object HOLDER {
        val INSTANCE = Singleton()
    }

    companion object {
        val instance: Singleton by lazy { HOLDER.INSTANCE }
    }
}
複製代碼

在上面的例子中,能夠看到經過 by lazy{} 確保只在第一次獲取實例時觸發,即 lazysynchronized 關鍵字的效果同樣。ide

固然對於單例模式,Kotlin 提供了 object 的實現方式。函數

object Singleton
複製代碼

僅僅一行代碼就能夠實現單例模式。post

object 聲明

object DataProviderManager {
    fun registerDataProvider(provider: DataProvider) {
        // ...
    }

    val allDataProviders: Collection<DataProvider>
        get() = // ...
}
複製代碼

就像聲明變量同樣,可是 object 的聲明不是表達式,不能進行賦值。object 聲明是線程安全的。spa

要使用 object 聲明的對象,能夠直接調用。

DataProviderManager.registerDataProvider(...)
複製代碼

一樣,object 聲明的類能夠具備父類。

object DefaultListener : MouseAdapter() {
    override fun mouseClicked(e: MouseEvent) { ... }

    override fun mouseEntered(e: MouseEvent) { ... }
}
複製代碼

總結

  • Kotlin 經過 object 關鍵字實現單例;
  • object 類能夠包含屬性、函數以及 init 塊;
  • 不容許有構造函數;
  • 不能以類的實例化方式實例化對象;
  • 當第一次使用對象提供延遲初始化時,該對象將被實例化;
  • object 是線程安全的。
相關文章
相關標籤/搜索