(Kotlin and Java)設(shè)計(jì)模式-單例模式

以最簡(jiǎn)單的module學(xué)習(xí)設(shè)計(jì)模式,理解最重要

設(shè)計(jì)模式持續(xù)更新中:http://www.itdecent.cn/p/e3c25095c31f
連著更了幾天,今天寫(xiě)個(gè)簡(jiǎn)單的,單例模式

前言

單例模式(Singleton Pattern)是 Java 中最簡(jiǎn)單的設(shè)計(jì)模式之一。

這種模式涉及到一個(gè)單一的類(lèi),該類(lèi)負(fù)責(zé)創(chuàng)建自己的對(duì)象,同時(shí)確保只有單個(gè)對(duì)象被創(chuàng)建。這個(gè)類(lèi)提供了一種訪問(wèn)其唯一的對(duì)象的方式,可以直接訪問(wèn),不需要實(shí)例化該類(lèi)的對(duì)象。

注意:

1、單例類(lèi)只能有一個(gè)實(shí)例。
2、單例類(lèi)必須自己創(chuàng)建自己的唯一實(shí)例。
3、單例類(lèi)必須給所有其他對(duì)象提供這一實(shí)例。

正文:

:由于單例模式是經(jīng)常用到的,這里就不提供demo了(懶。。。)
本文就總結(jié)了Java中單例模式的幾種實(shí)現(xiàn)方式,并比較了它們的優(yōu)缺點(diǎn)

1. 最簡(jiǎn)單的實(shí)現(xiàn)---餓漢式

Java

/**
 * 餓漢式
 */
public class Single {
    private static Single single = new Single();

    private Single() {
    }

    public static Single getInstance() {
        return single;
    }
}

寫(xiě)一個(gè)單例(不管什么形式),主要注意點(diǎn)如下幾點(diǎn)(該種方式不存在線程安全的問(wèn)題,其是線程安全的)

    1. 成員變量 single 要聲明成靜態(tài)的(static),因?yàn)樾枰陟o態(tài)方法getInstance()中訪問(wèn);
    1. 構(gòu)造方法要聲明成私有,不然如何保證單例;
    1. getInstance()要聲明成 public static的。

Kotlin

/**
 * 餓漢式
 */
object Single {
}

有童鞋要說(shuō)了,這什么都沒(méi)寫(xiě)呀。對(duì),餓漢式在Kotlin中,只需要一個(gè)object修飾符就行了,這就是Kotlin非常厲害的地方。

2.性能優(yōu)化(lazy load)——懶漢式

餓漢式的方式雖然簡(jiǎn)單,但是是基于classloader加載的,其在該類(lèi)第一次加載進(jìn)內(nèi)存時(shí)就會(huì)初始化單例對(duì)象。這樣,無(wú)論該對(duì)象是否被使用,都會(huì)創(chuàng)建一個(gè)single對(duì)象。

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原生寫(xiě)法
       */
      val INSTANCL_1 by lazy(LazyThreadSafetyMode.NONE) {
          Single()
      }
      /**
       * 翻譯java的寫(xiě)法
       */
      private var single: Single? = null

      fun getInstance(): Single {
          if (single == null) {
              single = Single()
          }
          return single!!
      }

  }
}

Kotlin這里有兩種寫(xiě)法,一種是純種,一種是變種。變種大家一看就明白,就是直接把Java的方式翻譯過(guò)來(lái)了。純種的我們使用了lazy,看英文就知道是懶加載的方式,傳入了一個(gè)LazyThreadSafetyMode.NONE,英文好的小伙伴一看就明白,這是線程不安全的意思。companion object的意思相當(dāng)于Java中public static。

3. 懶漢式——線程安全(1)

因?yàn)閼袧h式的出現(xiàn),雖然解決了餓漢式的不足,但也出現(xiàn)了多線程的問(wèn)題。于是解決懶漢式的方式就出現(xiàn)了,那就是我們熟知的加鎖Synchronized。
Java

/**
 * 懶漢式 --- 線程安全
 * 使用synchronized保證線程安全
 * 雖然線程安全了,但因?yàn)槭褂胹ynchronized關(guān)鍵字使加鎖效率不高
 */
public class Single {
    private static Single instance;

    private Single() {
    }

    public static synchronized Single getInstance() {
        if (instance == null) {
            instance = new Single();
        }
        return instance;
    }
}

Kotlin


/**
 * 懶漢式 --- 線程安全
 * 使用synchronized保證線程安全
 * 雖然線程安全了,但因?yàn)槭褂胹ynchronized關(guān)鍵字使加鎖效率不高
 * 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

/**
 * 懶漢式 --- 線程安全 雙重校驗(yàn)鎖
 */
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;
    }

}

但是上面的單例都有其缺陷:當(dāng)反序列化和使用java的反射機(jī)制時(shí),單例無(wú)法得到保證,那么,解決該問(wèn)題,我們可以使用Enum(枚舉)。
Kotlin

/**
 * 懶漢式 --- 線程安全 雙重校驗(yàn)鎖
 */
class Single private constructor() {

    companion object {

        /**
         * Kotlin原生寫(xiě)法
         */
        val INSTANCE_1 by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            Single()
        }
        /**
         * 翻譯java寫(xiě)法(變種方法)
         */
       private var single: Single? = null

        fun getInstance(): Single {
            if (single == null) {
                synchronized(Single::class.java) {
                    if (single == null) {
                        single = Single()
                    }
                }
            }
            return single!!
        }
    }

}

Kotlin原生的,我們只改變了lazy的括號(hào)的值,mode = LazyThreadSafetyMode.SYNCHRONIZED就是鎖的意思,英文好的童鞋一眼就明白了。

5. 枚舉實(shí)現(xiàn)

這種方式是Effective Java作者Josh Bloch 提倡的方式,它不僅能避免多線程同步問(wèn)題,而且還能防止反序列化和反射機(jī)制重新創(chuàng)建新的對(duì)象,不過(guò),JDK1.5中才加入enum特性, 這種方式只能在1.5之后使用。(但是Android官網(wǎng)不建議使用enums,占用內(nèi)存多(Enums often require more than twice as much memory as static constants.))
Java

/**
 * 枚舉實(shí)現(xiàn)
 */
public enum Single {
    INSTANCE;

    public void method() {
    }
}

Kotlin

/**
 * 枚舉實(shí)現(xiàn)
 */
public enum Single {
    INSTANCE;

    public void method() {
    }
}

6.內(nèi)部類(lèi)式

雖然不怎么被大家使用,但是覺(jué)得還是比較好。還是要說(shuō)一下的
Java

/**
 * 內(nèi)部類(lèi)實(shí)現(xiàn)
 */
public class Single {
    private Single() {
    }

    private static class Hodler {
        private static Single single = new Single();
    }

    public static Single getInstance() {
        return Hodler.single;
    }
}

內(nèi)部類(lèi)Holder,里面有外部的實(shí)例。很多童鞋可能要問(wèn),這怎么就滿足懶漢式和線程安全呢?當(dāng)我們應(yīng)用初始化時(shí),getInstance沒(méi)有被調(diào)用,就沒(méi)有實(shí)例對(duì)象,那就滿足了懶漢式。當(dāng)我們調(diào)用getInstance的時(shí)候,Java虛擬機(jī)為了保證類(lèi)加載的安全性,所以這里就保證了線程安全。這種寫(xiě)法是不是驚呆了?那Kotlin又是怎么樣寫(xiě)的呢?

/**
 * 內(nèi)部類(lèi)實(shí)現(xiàn)
 */
class Single private constructor() {
    companion object {
        fun getInstance(): Single {
            return Hodler.single
        }
    }

    private object Hodler {
        val single = Single()
    }
}

很簡(jiǎn)單,內(nèi)部用object創(chuàng)建一個(gè)內(nèi)部Holder單例,外部一個(gè)getInstance來(lái)獲取的方法。也相當(dāng)于是Java翻譯過(guò)來(lái)的方式。


如果你對(duì)此感興趣,可訂閱(感謝你的關(guān)注):


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容