Kotlin单例模式多种写法大分析

作者: 遛狗的程序员 | 来源:发表于2018-08-07 22:46 被阅读41次

    前言:

    今天,在项目开发中,又运用到了单例模式另外一种Kotlin写法,于是决定记录下来,以供参考。

    几种单例模式:
    • 饿汉式
    • 双重校验懒汉式
    • 静态内部类式

    1. 饿汉式

    /**
     * 作者:huangchen on 2018/8/7 21:48
     * 邮箱:huangcftt@gmail.com
     */
    //java实现
    public class PayManager {
        private static PayManager payManager = new PayManager();
    
        public static PayManager getPayManager() {
            return payManager;
        }
    
        private PayManager(){
    
        }
    }
    
    /**
     * 作者:huangchen on 2018/8/7 21:55
     * 邮箱:huangcftt@gmail.com
     */
    //Kotlin实现
    object PayServiceManager
    

    是不是大吃一惊。我靠一个object 关键字就完成相同的功能?一行代码?

    Kotlin的对象声明学习了Kotlin的小伙伴肯定知道,在Kotlin中类没有静态方法。如果你需要写一个可以无需用一个类的实例来调用,但需要访问类内部的函数(例如,工厂方法,单例等),你可以把该类声明为一个对象。该对象与其他语言的静态成员是类似的。

    对象声明的初始化过程是线程安全的。

    查看kotlin Bytecode 后 Decompile后:

    
    @Metadata(
       mv = {1, 1, 9},
       bv = {1, 0, 2},
       k = 1,
       d1 = {"\u0000\f\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\bÆ\u0002\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002¨\u0006\u0003"},
       d2 = {"Lcn/yonghui/shop/shopapplication/pay/config/PayServiceManager;", "", "()V", "production sources for module app"}
    )
    public final class PayServiceManager {
       public static final PayServiceManager INSTANCE;
    
       static {
          PayServiceManager var0 = new PayServiceManager();
          INSTANCE = var0;
       }
    }
    
    

    通过以上代码,我们了解事实就是这个样子的,使用Kotlin"object"进行对象声明与我们的饿汉式单例的代码基本是相同的。

    2. 双重校验懒汉式

    //java 代码
     private PayManager(){
    
       }
    
       private  volatile static PayManager payManager;
    
        public static  PayManager getPayManager() {
            if(payManager == null){
                synchronized (PayManager.class){
                    if(payManager == null){
                        payManager = new PayManager()
                    }
                }
            }
            return payManager;
        }
    
    //kotlin实现
    class PayServiceManager private constructor() {
        companion object {
            val instance: PayServiceManager by lazy {
                PayServiceManager()
            }
        }
    }
    
    • 显式声明构造方法为private
    • companion object用来在class内部声明一个对象
    • PayServiceManager的实例instance 通过lazy来实现懒汉式加载
    • lazy默认情况下是线程安全的,这就可以避免多个线程同时访问生成多个实例的问题

    知识点:

    • lazy()是接受一个 lambda 并返回一个 Lazy <T> 实例的函数,返回的实例可以作为实现延迟属性的委托: 第一次调用 get() 会执行已传递给 lazy() 的 lambda 表达式并记录结果, 后续调用 get() 只是返回记录的结果。
    • 默认情况下,对于 lazy 属性的求值是同步锁的(synchronized):该值只在一个线程中计算,并且所有线程会看到相同的值。如果初始化委托的同步锁不是必需的,这样多个线程可以同时执行,那么将 LazyThreadSafetyMode.PUBLICATION 作为参数传递给 lazy() 函数。 而如果你确定初始化将总是发生在单个线程,那么你可以使用 LazyThreadSafetyMode.NONE 模式, 它不会有任何线程安全的保证以及相关的开销。
      有兴趣可参考:lazy讲解

    3. 静态内部类式

    //Java实现
    private PayManager(){
    
       }
       private static class PayManagerHolder{
           private static PayManager payManager = new PayManager();
       }
       public static PayManager getPayManager(){
           return PayManagerHolder.payManager;
       }
    
    //kotlin实现
    class PayServiceManager private constructor() {
        companion object {
            val instance =PayServiceManagerHolder.payServiceManager
        }
    
        private object PayServiceManagerHolder {
            val payServiceManager = PayServiceManager()
        }
    }
    

    静态内部类java代码和Kotlin代码基本类似。

    总结:

    对于资源占用和实例初始化时间比较少的时候,应该使用object形式的饿汉式加载。否则的话使用懒汉式。

    参考:

    声明:此为原创,转载请联系作者


    作者:微信公众号添加公众号-遛狗的程序员 ,或者可以扫描以下二维码关注相关技术文章。

    qrcode_for_gh_1ba0785324d6_430.jpg

    当然喜爱技术,乐于分享的你也可以可以添加作者微信号:

    WXCD.jpeg

    相关文章

      网友评论

        本文标题:Kotlin单例模式多种写法大分析

        本文链接:https://www.haomeiwen.com/subject/tmuzvftx.html