单例模式简介与kotlin的单例模式具体实现

Posted by

今天来说说设计模式中非常重要的一种设计模式,单例模式。然后再来讲讲在kotlin中是怎么来实现单例模式,以及在实现单例的过程中,需要注意的几个问题。

第一:什么是单例模式?

单例模式的概念虽然很简单,但是他真的十分重要。单例模式几乎是我在面试程序员时,必须会考的一道题了。那么到底什么是单例模式呢?

我们都知道,在在面向对象的编程语言中,类是对象的实例。当我们要实例化一个类时,很多编程语言会用到new这个关键字,来实例化对象。这个实例化的过程,实际上就是把类的文件读取到内存里。如果多次实例化同一个类,那么我们需要多次读取类的文件,然后加载到内存里调用。

单例模式,实际上就是保证一个类只会被实例化一次的方法。当其他代码需要实例化这个类时,只需要返回这个类的对象即可。

这个设计模式,对于性能的优化至关重要。某个类如果过于庞大,当多次实例化这个类的时候,会消耗大量不必要的资源,这个时候必须使用单例模式。

第二:kotlin如何实现单例模式呢?

kotlin实现单例模式,真的非常非常的简单。在kotlin里,是不需要new关键词来创造类的实例。而是通过kotlin类已经封装的get()方法直接获取类的实例。所以,当我们要实现kotlin的单例模式,有一个最简单的方法。就是通过定义类的get()方法,让他每次只返回类本身即可。真的是超级超级简单!

我查看了谷歌官方的安卓代码,那里用kotlin实现单例,还是使用java的方式,哈哈。根本,就没有利用到kotlin本身的语法特性。

 // 这个就是单例模式,超级简单
@Component
class BaseMongoRepository {

    companion object {
        private var instance: BaseMongoRepository?= BaseMongoRepository()
        get() = BaseMongoRepository.instance
    }
}

以上就是kotlin实现单例的一个比较简单的实现方式。在伴身对象里定义一个变量,然后自定义类的get()方法。保证每次实例化类的时候,都只返回类的实例。

第三步:为kotlin的单例模式添加同步注解

// 这个就是单例模式,超级简单
@Component
class BaseMongoRepository {

    companion object {  
        private var instance: BaseMongoRepository?= BaseMongoRepository()
        // 为了防止多线程环境下get()方法无法保证返回同一个实例,必须给get()方法添加同步注解。
        @Synchronized
        get() = BaseMongoRepository.instance 
    } 
}

如图所示,为get()方法添加了同步注解,该注解将防止多线程环境下,多个请求同时要求实例化类时,保证只返回一个实例。

第四步:实例化类时延迟加载变量,保证单例的唯一

在如图所示的代码中,我们会看到在伴身对象里,我们需要先声明一个私有的可空类型的变量,用于保存当前类。为这个实例变量添加@Lazy注解,将会保证这个变量永远只会在get()方法执行后,再执行类的实例化。

// 这个就是单例模式,超级简单
@Component
class BaseMongoRepository {

    companion object {  
        // Lazy注解保证先初始化类再执行get()方法
        @Lazy 
        private var instance: BaseMongoRepository?= BaseMongoRepository()
        // 为了防止多线程环境下get()方法无法保证返回同一个实例,必须给get()方法添加同步注解。
        @Synchronized
        get() = BaseMongoRepository.instance 
    } 
}

第五步:保证kotlin伴身对象的属性和方法编译为Jvm的静态属性和方法

kotlin本身是没有静态属性和方法的,通过伴身对象的方式来实现。伴身对象内的属性和方法,对应java的静态属性和方法。为了保证编译器将kotlin的属性和方法编译为Jvm真正的静态方法,需要通过添加@Jvmstatic注解来实现。

// 这个就是单例模式,超级简单
@Component
class BaseMongoRepository {

    companion object {  
       @Lazy      // Lazy注解保证先初始化类再执行get()方法
       @JvmStatic // JvmStatic注解保证kotlin的伴身对象内的函数和变量,会编译为JVM真正的静态成员
       private var instance: BaseMongoRepository?= BaseMongoRepository() 

       @Synchronized // 为了防止多线程环境下get()方法无法保证返回同一个实例,必须给get()方法添加同步注解。
       @JvmStatic    // JvmStatic注解保证kotlin的伴身对象内的函数和变量,会编译为JVM真正的静态成员
       @Synchronized get() = BaseMongoRepository.instance
    }
}

第六步:单例模式的扩展应用

有时候,我们不只是需要一个类只有一个对象。当我们需要一个类可以被实例化成几个对象时。可以使用map的方式来实现。map的每一个值可以储存一个实例。每一次实例化类,返回一个实例。这个算是单例模式的扩展应用吧,因为用的少,这里就不写具体的实现了。😄,代码有点多。

文武双全的总结

水平有限,对单例模式的理解可能存在不足的地方,希望大家批评指正!

参考资料:

IBM官方资料:Java编程设计模式第 1 部分单例模式

One comment

Leave a Reply

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据