kotlin经典单例实现
我们都知道 Kotlin
为我们实现单例提供了很方便的实现,一个关键词就可以搞定:那就是 object
object SomeSingleton
反编译成 Java
代码:
public final class SomeSingleton {
public static final SomeSingleton INSTANCE;
private SomeSingleton() {
INSTANCE = (SomeSingleton)this;
}
static {
new SomeSingleton();
}
}
可以看出,是通过静态内部类实现的。它是《java并发编程实践》推荐的实现单例的方式。因为这种方式不仅能够保证单例对象的唯一性,同时也延迟了单例的实例化。
关于 java
的几种单例设计模式实现方法,可以参考笔者之前写的一篇博客:
带参优雅实现
自动化在带来快捷便利的同时,就意味着失去一定的灵活性。
object
方式的实现带来的一个局限就是不能自由传参。因为 Kotlin
的 object
关键字不允许存在任何构造函数。
或许你会想到可以通过注入的方式去实现,但是这样还是太麻烦,如果忘记去调用这个方法就会出问题,相信他人也不太喜欢这样的方式去获取你写的单例对象。
有没有更为优雅的方式实现呢?
当然是有的。
我们需要参考 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)
好了,游戏结束,就这么简单~
网友评论