- 原文作者 : Abhilash Das
- 原文链接 : Singleton class in Kotlin
- 译者 : 邓士伟
- 校对者: 邓士伟
- 状态 : 完成
如果我想定义单例模式,那么它应该是这样的:
单例是一种软件设计模式,它保证一个类只有一个实例,并且该类提供对该实例的全局访问控制。
在 Java 中,通常这样写:
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
但是上面的代码在多线程场景下是有缺陷的。如果两个线程同时获取实例,则可能会创建两个实例。所以对于上面的代码我们需要改造。
class Singleton {
private static Singleton instance = null;
private Singleton() {
}
private synchronized static void createInstance() {
if (instance == null) {
instance = new Singleton();
}
}
public static Singleton getInstance() {
if (instance == null) createInstance();
return instance;
}
}
通过 synchronized 关键字可以确保在创建 instance 时没有线程冲突,只创建一个实例。
在 Kotlin 中可以这样实现:
class Singleton private constructor() {
private object HOLDER {
val INSTANCE = Singleton()
}
companion object {
val instance: Singleton by lazy { HOLDER.INSTANCE }
}
}
在上面的例子中,可以看到通过 by lazy{} 确保只在第一次获取实例时触发,即 lazy 和 synchronized 关键字的效果一样。
当然对于单例模式,Kotlin 提供了 object 的实现方式。
object Singleton
仅仅一行代码就可以实现单例模式。
object 声明
object DataProviderManager {
fun registerDataProvider(provider: DataProvider) {
// ...
}
val allDataProviders: Collection<DataProvider>
get() = // ...
}
就像声明变量一样,但是 object 的声明不是表达式,不能进行赋值。object 声明是线程安全的。
要使用 object 声明的对象,可以直接调用。
DataProviderManager.registerDataProvider(...)
同样,object 声明的类可以具有父类。
object DefaultListener : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) { ... }
override fun mouseEntered(e: MouseEvent) { ... }
}
总结
Kotlin通过object关键字实现单例;object类可以包含属性、函数以及init块;- 不允许有构造函数;
- 不能以类的实例化方式实例化对象;
- 当第一次使用对象提供延迟初始化时,该对象将被实例化;
object是线程安全的。