[译]Kotlin 中的单例模式

若是我想定义单例模式,那么它应该是这样的:java

单例是一种软件设计模式,它保证一个类只有一个实例,而且该类提供对该实例的全局访问控制。git

Java 中,一般这样写:github

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{} 确保只在第一次获取实例时触发,即 lazysynchronized 关键字的效果同样。ide

固然对于单例模式,Kotlin 提供了 object 的实现方式。函数

object Singleton
复制代码

仅仅一行代码就能够实现单例模式。post

object 声明

object DataProviderManager {
    fun registerDataProvider(provider: DataProvider) {
        // ...
    }

    val allDataProviders: Collection<DataProvider>
        get() = // ...
}
复制代码

就像声明变量同样,可是 object 的声明不是表达式,不能进行赋值。object 声明是线程安全的。spa

要使用 object 声明的对象,能够直接调用。

DataProviderManager.registerDataProvider(...)
复制代码

一样,object 声明的类能够具备父类。

object DefaultListener : MouseAdapter() {
    override fun mouseClicked(e: MouseEvent) { ... }

    override fun mouseEntered(e: MouseEvent) { ... }
}
复制代码

总结

  • Kotlin 经过 object 关键字实现单例;
  • object 类能够包含属性、函数以及 init 块;
  • 不容许有构造函数;
  • 不能以类的实例化方式实例化对象;
  • 当第一次使用对象提供延迟初始化时,该对象将被实例化;
  • object 是线程安全的。
相关文章
相关标签/搜索