21.单例模式(大话设计模式kotlin版)

单例模式


  • 定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

通常我们可以通过一个全局变量使得一个对象可以被访问,但它不能防止被实例化多个对象。一个最好的解决方式是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。

21.单例模式(大话设计模式kotlin版)_第1张图片

常用的几种写法


懒汉式单例模式

  • 定义:在第一次被引用的时,才会将自己实例化。

  • 参考代码:

/**
 * @create on 2020/6/14 12:10
 * @description 懒汉式 单例模式
 * @author mrdonkey
 */
class LazySingleton {
    private constructor() //私有构造,防止外界实例化它

    companion object {
        private var instance: LazySingleton? = null

        @JvmStatic
        fun getInstance(): LazySingleton {//获取唯一实例的入口
            if (instance == null) {//如果为空,则新建一个实例返回,反之返回它
                instance = LazySingleton()
            }
            return instance as LazySingleton
        }
    }
}
  • 好处:通过SingleTon模式封装类的实例,可以对唯一实例的进行受控访问。

多线程时的单例

在多线程的程序中,多个线程同时访问获取类实例的getInstance方法时,可能造成的创建多个实例。

懒汉式加锁的单例模式
  • 简单概览:给进入该方法体的当前进程加一把锁,在该进程调用该方法的过程中,其他进程若试图进入该方法则将会等待,直到前面的进程执行完,锁释放后才进会方法体。

  • 基本代码:

/**
 * @create on 2020/6/14 12:45
 * @description 懒汉式加锁单例模式
 * @author mrdonkey
 */
class LazyLockSingleton {
    private constructor()

    companion object {
        private var instance: LazyLockSingleton? = null

        @JvmStatic
        fun getInstance(): LazyLockSingleton {
            synchronized(this) {
                if (instance == null) {
                    instance = LazyLockSingleton()
                }
            }
            return instance as LazyLockSingleton
        }
    }
}
  • 不足:进程每次进入方法都会被上锁,这样会有些性能损耗,可以先判断当前实例是否为空再去加锁,下面的双重检锁的写法就是解决这个不足。
懒汉式双重检锁的单例模式
  • 双重检锁(Double-Check-Locking):为了不让线程每次都加锁,而只是在实例未创建的时候才去加锁,保证线程安全。
  • 基本代码:
/**
 * @create on 2020/6/14 12:17
 * @description 双重检索、饿汉式 单例模式 针对多线程的情况 保证线程安全
 * @author mrdonkey
 */
class LazyDCLSingleton {
    private constructor()

    companion object {
        private var instance: LazyDCLSingleton? = null

        @JvmStatic
        fun getInstance(): LazyDCLSingleton {
            if (instance == null) {//第一重
                synchronized(this) {
                    if (instance == null) {//第二重
                        instance = LazyDCLSingleton()
                    }
                }
            }
            return instance as LazyDCLSingleton
        }
    }
}
  • 疑问:为什么需要两次实例为空的判断呢?
    因为,多线程中,第一个线程先进入该方法并加锁处理已经进入第二重,第二个线程此时是可以进入第一重为空的判断里,等到第一个线程创建了一个实例,第二个线程才可以进入,若不再加一重为空的判断,那么第二个线程也会重新创建一个实例,导致第一个实例被覆盖掉了!

饿汉式单例模式

  • 定义:在类被加载时就去实例化自己。

  • 基本代码:

/**
 * @create on 2020/6/14 12:09
 * @description 饿汉式 单例模式
 * @author mrdonkey
 */
class  HungrySingleton {
    private constructor()

    companion object {
        private val instance: HungrySingleton = HungrySingleton()//val 引用不可更改,类加载时就去实例化,因为一般来说类之后加载一次。

        @JvmStatic
        fun getInstance(): HungrySingleton {
            return instance
        }
    }
  • 优势:相比懒汉式单例模式,它是线程安全的单例模式,不需要做加锁处理。

  • 不足:提前占用系统资源

枚举类单例

/**
 * @create on 2020/6/14 13:00
 * @description 枚举类定义的对象都是单例的,无偿提供序列化支持。
 * @author mrdonkey
 */
enum class EnumSingleton {
    INSTANCE
}

你可能感兴趣的:(设计模式)