单例设计模式就不用多介绍了,说是大家最熟悉的设计模式也不为过,在Effective Java中有两条与之相关:第3条用私有构造器或者枚举类型强化 Singleton 属性,第4条通过私有构造器强化不可实例化的能力。单例模式的关键在于保证多线程下仍然是单例,常见的做法有:
- 静态变量存储单例(饿汉模式)
- Double-checked locking
- 静态类Holder
- 枚举类
众所周知,Kotlin使用object
关键字来实现单例,这种实现方式实际上是方式1饿汉模式,并且仅适用于只有默认构造函数的类,如果构造函数包含有参数,是不能使用object
关键字的,此时还得使用方式2:
class PlantRepository private constructor(private val plantDao: PlantDao) {
fun getPlants() = plantDao.getPlants()
companion object {
@Volatile private var instance: PlantRepository? = null
fun getInstance(plantDao: PlantDao) =
instance ?: synchronized(this) {
instance ?: PlantRepository(plantDao).also { instance = it }
}
}
}
这就是Kotlin味道的Double-checked locking,本质上跟Java的写法是一样的,只是利用了?:
操作符以及also
扩展函数之后变得更加简洁。至于为什么需要在instance
上加上注解@Volatile
(即Java的关键字volatile
),可以查看维基百科Double-checked locking。