美文网首页Android开发程序员我爱编程
(Kotlin and Java)设计模式-单例模式

(Kotlin and Java)设计模式-单例模式

作者: SYfarming | 来源:发表于2018-06-08 09:49 被阅读16次

    以最简单的module学习设计模式,理解最重要

    设计模式持续更新中:https://www.jianshu.com/p/e3c25095c31f
    连着更了几天,今天写个简单的,单例模式

    前言

    单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。

    这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

    注意:

    1、单例类只能有一个实例。
    2、单例类必须自己创建自己的唯一实例。
    3、单例类必须给所有其他对象提供这一实例。

    正文:

    :由于单例模式是经常用到的,这里就不提供demo了(懒。。。)
    本文就总结了Java中单例模式的几种实现方式,并比较了它们的优缺点

    1. 最简单的实现---饿汉式

    Java

    /**
     * 饿汉式
     */
    public class Single {
        private static Single single = new Single();
    
        private Single() {
        }
    
        public static Single getInstance() {
            return single;
        }
    }
    

    写一个单例(不管什么形式),主要注意点如下几点(该种方式不存在线程安全的问题,其是线程安全的)

      1. 成员变量 single 要声明成静态的(static),因为需要在静态方法getInstance()中访问;
      1. 构造方法要声明成私有,不然如何保证单例;
      1. getInstance()要声明成 public static的。

    Kotlin

    /**
     * 饿汉式
     */
    object Single {
    }
    

    有童鞋要说了,这什么都没写呀。对,饿汉式在Kotlin中,只需要一个object修饰符就行了,这就是Kotlin非常厉害的地方。

    2.性能优化(lazy load)——懒汉式

    饿汉式的方式虽然简单,但是是基于classloader加载的,其在该类第一次加载进内存时就会初始化单例对象。这样,无论该对象是否被使用,都会创建一个single对象。

    Java

    
    /**
     * 懒汉式 --- 非线程安全
     */
    public class Single {
        private static Single single;
    
        private Single() {
        }
    
        public static Single getInstance() {
            if (single == null) {
                single = new Single();
            }
            return single;
        }
    }
    

    Kotlin

    /**
    * 懒汉式 --- 非线程安全
    */
    class Single private constructor() {
      companion object {
          /**
           * Kotlin原生写法
           */
          val INSTANCL_1 by lazy(LazyThreadSafetyMode.NONE) {
              Single()
          }
          /**
           * 翻译java的写法
           */
          private var single: Single? = null
    
          fun getInstance(): Single {
              if (single == null) {
                  single = Single()
              }
              return single!!
          }
    
      }
    }
    

    Kotlin这里有两种写法,一种是纯种,一种是变种。变种大家一看就明白,就是直接把Java的方式翻译过来了。纯种的我们使用了lazy,看英文就知道是懒加载的方式,传入了一个LazyThreadSafetyMode.NONE,英文好的小伙伴一看就明白,这是线程不安全的意思。companion object的意思相当于Java中public static。

    3. 懒汉式——线程安全(1)

    因为懒汉式的出现,虽然解决了饿汉式的不足,但也出现了多线程的问题。于是解决懒汉式的方式就出现了,那就是我们熟知的加锁Synchronized。
    Java

    /**
     * 懒汉式 --- 线程安全
     * 使用synchronized保证线程安全
     * 虽然线程安全了,但因为使用synchronized关键字使加锁效率不高
     */
    public class Single {
        private static Single instance;
    
        private Single() {
        }
    
        public static synchronized Single getInstance() {
            if (instance == null) {
                instance = new Single();
            }
            return instance;
        }
    }
    

    Kotlin

    
    /**
     * 懒汉式 --- 线程安全
     * 使用synchronized保证线程安全
     * 虽然线程安全了,但因为使用synchronized关键字使加锁效率不高
     * Kotlin使用@Synchronized注解加锁
     */
    class Single private constructor() {
        companion object {
            private var single: Single? = null
    
            @Synchronized
            fun getInstance(): Single {
                if (single == null) {
                    single = Single()
                }
                return single!!
            }
        }
    
    }
    

    4. 懒汉式——线程安全(2):效率更高

    Java

    /**
     * 懒汉式 --- 线程安全 双重校验锁
     */
    public class Single {
        private static Single single;
    
        private Single() {
        }
    
        public static Single getInstance() {
            if (single == null) {
                synchronized (Single.class) {
                    if (single == null) {
                        single = new Single();
                    }
                }
            }
            return single;
        }
    
    }
    

    但是上面的单例都有其缺陷:当反序列化和使用java的反射机制时,单例无法得到保证,那么,解决该问题,我们可以使用Enum(枚举)。
    Kotlin

    /**
     * 懒汉式 --- 线程安全 双重校验锁
     */
    class Single private constructor() {
    
        companion object {
    
            /**
             * Kotlin原生写法
             */
            val INSTANCE_1 by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
                Single()
            }
            /**
             * 翻译java写法(变种方法)
             */
           private var single: Single? = null
    
            fun getInstance(): Single {
                if (single == null) {
                    synchronized(Single::class.java) {
                        if (single == null) {
                            single = Single()
                        }
                    }
                }
                return single!!
            }
        }
    
    }
    

    Kotlin原生的,我们只改变了lazy的括号的值,mode = LazyThreadSafetyMode.SYNCHRONIZED就是锁的意思,英文好的童鞋一眼就明白了。

    5. 枚举实现

    这种方式是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化和反射机制重新创建新的对象,不过,JDK1.5中才加入enum特性, 这种方式只能在1.5之后使用。(但是Android官网不建议使用enums,占用内存多(Enums often require more than twice as much memory as static constants.))
    Java

    /**
     * 枚举实现
     */
    public enum Single {
        INSTANCE;
    
        public void method() {
        }
    }
    

    Kotlin

    /**
     * 枚举实现
     */
    public enum Single {
        INSTANCE;
    
        public void method() {
        }
    }
    

    6.内部类式

    虽然不怎么被大家使用,但是觉得还是比较好。还是要说一下的
    Java

    /**
     * 内部类实现
     */
    public class Single {
        private Single() {
        }
    
        private static class Hodler {
            private static Single single = new Single();
        }
    
        public static Single getInstance() {
            return Hodler.single;
        }
    }
    

    内部类Holder,里面有外部的实例。很多童鞋可能要问,这怎么就满足懒汉式和线程安全呢?当我们应用初始化时,getInstance没有被调用,就没有实例对象,那就满足了懒汉式。当我们调用getInstance的时候,Java虚拟机为了保证类加载的安全性,所以这里就保证了线程安全。这种写法是不是惊呆了?那Kotlin又是怎么样写的呢?

    /**
     * 内部类实现
     */
    class Single private constructor() {
        companion object {
            fun getInstance(): Single {
                return Hodler.single
            }
        }
    
        private object Hodler {
            val single = Single()
        }
    }
    

    很简单,内部用object创建一个内部Holder单例,外部一个getInstance来获取的方法。也相当于是Java翻译过来的方式。


    如果你对此感兴趣,可订阅(感谢你的关注):


    相关文章

      网友评论

        本文标题:(Kotlin and Java)设计模式-单例模式

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