美文网首页设计模式也是一种艺术kotlin
Kotlin带参单例模式的优雅实现

Kotlin带参单例模式的优雅实现

作者: 树獭非懒 | 来源:发表于2020-06-22 08:45 被阅读0次

    kotlin经典单例实现

    我们都知道 Kotlin 为我们实现单例提供了很方便的实现,一个关键词就可以搞定:那就是 object

    object SomeSingleton
    

    反编译成 Java 代码:

    public final class SomeSingleton {
       public static final SomeSingleton INSTANCE;
    
       private SomeSingleton() {
          INSTANCE = (SomeSingleton)this;
       }
    
       static {
          new SomeSingleton();
       }
    }
    
    

    可以看出,是通过静态内部类实现的。它是《java并发编程实践》推荐的实现单例的方式。因为这种方式不仅能够保证单例对象的唯一性,同时也延迟了单例的实例化。

    关于 java 的几种单例设计模式实现方法,可以参考笔者之前写的一篇博客:

    设计模式之单例模式

    带参优雅实现

    自动化在带来快捷便利的同时,就意味着失去一定的灵活性。

    object 方式的实现带来的一个局限就是不能自由传参。因为 Kotlinobject 关键字不允许存在任何构造函数。

    或许你会想到可以通过注入的方式去实现,但是这样还是太麻烦,如果忘记去调用这个方法就会出问题,相信他人也不太喜欢这样的方式去获取你写的单例对象。

    有没有更为优雅的方式实现呢?

    当然是有的。

    我们需要参考 Kotlin 标准库中的 lazy() 函数的实现思路。

    把创建和初始化带有参数的单例的逻辑封装起来。并通过双重检查锁定算法实现逻辑的线程安全。

    open class SingletonHolder<out T, in A>(creator: (A) -> T) {
    
        private var creator: ((A) -> T)? = creator
        @Volatile
        private var instance: T? = null
    
        fun getInstance(arg: A): T {
            val i = instance
            if (i != null) {
                return i
            }
    
            return synchronized(this) {
                val i2 = instance
                if (i2 != null) {
                    i2
                } else {
                    val created = creator!!(arg)
                    instance = created
                    creator = null
                    created
                }
            }
        }
        
        //对上述方法的一种更简洁的写法
        fun getInstance2(arg: A): T =
            instance ?: synchronized(this) {
                instance ?: creator!!(arg).apply { 
                    instance = this 
                }
            }
    
    }
    

    这个类一撸完,它就像一个爸爸的存在。有了它接下来我们实现单例就变得异常简单,举个栗子

    我想实现一个带 context 参数的 SkinManager 单例

    class SkinManager private constructor(context: Context) {
        companion object : SingletonHolder<SkinManager, Context>(::SkinManager)
    }
    

    使用方式:

    SkinManager.getInstance(context)
    

    好了,游戏结束,就这么简单~

    相关文章

      网友评论

        本文标题:Kotlin带参单例模式的优雅实现

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