Kotlin帶參單例模式的優(yōu)雅實(shí)現(xiàn)

kotlin經(jīng)典單例實(shí)現(xiàn)

我們都知道 Kotlin 為我們實(shí)現(xiàn)單例提供了很方便的實(shí)現(xiàn),一個(gè)關(guān)鍵詞就可以搞定:那就是 object

object SomeSingleton

反編譯成 Java 代碼:

public final class SomeSingleton {
   public static final SomeSingleton INSTANCE;

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

   static {
      new SomeSingleton();
   }
}

可以看出,是通過(guò)靜態(tài)內(nèi)部類實(shí)現(xiàn)的。它是《java并發(fā)編程實(shí)踐》推薦的實(shí)現(xiàn)單例的方式。因?yàn)檫@種方式不僅能夠保證單例對(duì)象的唯一性,同時(shí)也延遲了單例的實(shí)例化。

關(guān)于 java 的幾種單例設(shè)計(jì)模式實(shí)現(xiàn)方法,可以參考筆者之前寫的一篇博客:

設(shè)計(jì)模式之單例模式

帶參優(yōu)雅實(shí)現(xiàn)

自動(dòng)化在帶來(lái)快捷便利的同時(shí),就意味著失去一定的靈活性。

object 方式的實(shí)現(xiàn)帶來(lái)的一個(gè)局限就是不能自由傳參。因?yàn)?Kotlinobject 關(guān)鍵字不允許存在任何構(gòu)造函數(shù)。

或許你會(huì)想到可以通過(guò)注入的方式去實(shí)現(xiàn),但是這樣還是太麻煩,如果忘記去調(diào)用這個(gè)方法就會(huì)出問(wèn)題,相信他人也不太喜歡這樣的方式去獲取你寫的單例對(duì)象。

有沒(méi)有更為優(yōu)雅的方式實(shí)現(xiàn)呢?

當(dāng)然是有的。

我們需要參考 Kotlin 標(biāo)準(zhǔn)庫(kù)中的 lazy() 函數(shù)的實(shí)現(xiàn)思路。

把創(chuàng)建和初始化帶有參數(shù)的單例的邏輯封裝起來(lái)。并通過(guò)雙重檢查鎖定算法實(shí)現(xiàn)邏輯的線程安全。

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
            }
        }
    }
    
    //對(duì)上述方法的一種更簡(jiǎn)潔的寫法
    fun getInstance2(arg: A): T =
        instance ?: synchronized(this) {
            instance ?: creator!!(arg).apply { 
                instance = this 
            }
        }

}

這個(gè)類一擼完,它就像一個(gè)爸爸的存在。有了它接下來(lái)我們實(shí)現(xiàn)單例就變得異常簡(jiǎn)單,舉個(gè)栗子

我想實(shí)現(xiàn)一個(gè)帶 context 參數(shù)的 SkinManager 單例

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

使用方式:

SkinManager.getInstance(context)

好了,游戲結(jié)束,就這么簡(jiǎn)單~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容