咱們都知道 Kotlin
爲咱們實現單例提供了很方便的實現,一個關鍵詞就能夠搞定:那就是 object
java
object SomeSingleton
複製代碼
反編譯成 Java
代碼:算法
public final class SomeSingleton {
public static final SomeSingleton INSTANCE;
private SomeSingleton() {
INSTANCE = (SomeSingleton)this;
}
static {
new SomeSingleton();
}
}
複製代碼
能夠看出,是經過靜態內部類實現的。它是《java併發編程實踐》推薦的實現單例的方式。由於這種方式不只可以保證單例對象的惟一性,同時也延遲了單例的實例化。編程
關於 java
的幾種單例設計模式實現方法,能夠參考筆者以前寫的一篇博客:設計模式
自動化在帶來快捷便利的同時,就意味着失去必定的靈活性。bash
object
方式的實現帶來的一個侷限就是不能自由傳參。由於 Kotlin
的 object
關鍵字不容許存在任何構造函數。併發
或許你會想到能夠經過注入的方式去實現,可是這樣仍是太麻煩,若是忘記去調用這個方法就會出問題,相信他人也不太喜歡這樣的方式去獲取你寫的單例對象。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)
複製代碼
好了,遊戲結束,就這麼簡單~