Kotlin帶參單例模式的優雅實現

kotlin經典單例實現

咱們都知道 Kotlin 爲咱們實現單例提供了很方便的實現,一個關鍵詞就能夠搞定:那就是 objectjava

object SomeSingleton
複製代碼

反編譯成 Java 代碼:算法

public final class SomeSingleton {
   public static final SomeSingleton INSTANCE;

   private SomeSingleton() {
      INSTANCE = (SomeSingleton)this;
   }

   static {
      new SomeSingleton();
   }
}

複製代碼

能夠看出,是經過靜態內部類實現的。它是《java併發編程實踐》推薦的實現單例的方式。由於這種方式不只可以保證單例對象的惟一性,同時也延遲了單例的實例化。編程

關於 java 的幾種單例設計模式實現方法,能夠參考筆者以前寫的一篇博客:設計模式

設計模式之單例模式安全

帶參優雅實現

自動化在帶來快捷便利的同時,就意味着失去必定的靈活性。bash

object 方式的實現帶來的一個侷限就是不能自由傳參。由於 Kotlinobject 關鍵字不容許存在任何構造函數。併發

或許你會想到能夠經過注入的方式去實現,可是這樣仍是太麻煩,若是忘記去調用這個方法就會出問題,相信他人也不太喜歡這樣的方式去獲取你寫的單例對象。app

有沒有更爲優雅的方式實現呢?函數

固然是有的。ui

咱們須要參考 Kotlin 標準庫中的 lazy() 函數的實現思路。

把建立和初始化帶有參數的單例的邏輯封裝起來。並經過雙重檢查鎖定算法實現邏輯的線程安全。

open class SingletonHolder<out T, in A>(creator: (A) -> T) {

    private var creator: ((A) -> T)? = creator
    @Volatile
    private var instance: T? = null

    fun getInstance(arg: A): T {
        val i = instance
        if (i != null) {
            return i
        }

        return synchronized(this) {
            val i2 = instance
            if (i2 != null) {
                i2
            } else {
                val created = creator!!(arg)
                instance = created
                creator = null
                created
            }
        }
    }
    
    //對上述方法的一種更簡潔的寫法
    fun getInstance2(arg: A): T =
        instance ?: synchronized(this) {
            instance ?: creator!!(arg).apply { 
                instance = this 
            }
        }

}
複製代碼

這個類一擼完,它就像一個爸爸的存在。有了它接下來咱們實現單例就變得異常簡單,舉個栗子

我想實現一個帶 context 參數的 SkinManager 單例

class SkinManager private constructor(context: Context) {
    companion object : SingletonHolder<SkinManager, Context>(::SkinManager)
}
複製代碼

使用方式:

SkinManager.getInstance(context)
複製代碼

好了,遊戲結束,就這麼簡單~

相關文章
相關標籤/搜索