咱们都知道 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)
复制代码
好了,游戏结束,就这么简单~