1. 程式人生 > >設計模式-單例模式(Singleton)詳解

設計模式-單例模式(Singleton)詳解

概述

  • 定義 : 保證一個類僅有一個例項, 並提供一個全域性訪問點
  • 又稱單件模式
  • 型別 : 建立型

適用場景

  • 想確保任何情況下都絕對只有一個例項

優點

  • 在記憶體裡只有一個例項, 減少了記憶體開銷
  • 可以避免對資源的多重佔用
  • 設定了全域性訪問點, 嚴格控制訪問

缺點

  • 沒有介面, 擴充套件困難

重點

  • 私有構造器
  • 執行緒安全問題
  • 延遲載入
  • 序列化和反序列化安全問題
  • 反射安全問題

分類

單例模式分為懶漢式和餓漢式, 懶漢式是採用了延遲初始化的方式進行建立物件的, 而餓漢式是在類載入的時候就進行初始化的, 下面分別對兩種模式進行一些分析

懶漢式

1. 首先, 來看一個最簡單的懶漢式單例程式碼實現 :

/**
 * 單例模式 : 懶漢模式
 *
 * @author 七夜雪
 * 2018/11/14 17:21
 */
public class SingletonLazyInit {
    private static SingletonLazyInit singleton;
	// 單例模式構造器必須是私有的,防止外部使用new關鍵字構造新物件
    private SingletonLazyInit() {
    }

    public static SingletonLazyInit getInstance()
{ if (null == singleton){ singleton = new SingletonLazyInit(); } return singleton; } }

上面的程式碼很簡單, 在單執行緒情況下也是沒有問題的, 但是在多執行緒的情況下就可能會存在問題, 比如說同時又兩個執行緒t1, t2同時呼叫SingletonLazyInit的getInstance方法, t1執行到singleton = new SingletonLazyInit();這一句但是還沒執行完時, t2判斷singleton仍然為空, 扔能進入if程式碼塊中, 這是t1物件建立成功並返回, 然後t2執行緒再進行物件建立, 這時t1和t2就獲取的就不是一個物件了


2. 對於上面這種情況, 最簡單的一種解決方案, 就是對getInstance方法進行加鎖, 增加Synchronized關鍵字, 對靜態方法進行加鎖, 鎖定的是當前類的class物件, 加鎖之後的程式碼如下:

/**
 * 單例模式 : 加鎖單例
 *
 * @author 七夜雪
 * 2018/11/14 17:21
 */
public class SingletonSynchronized {
    private static SingletonSynchronized singleton;

    private SingletonSynchronized() {
    }

    // 寫法一
    public static synchronized SingletonSynchronized getInstance(){
        if (null == singleton){
            singleton = new SingletonSynchronized();
        }
        return singleton;
    }

      // 寫法二
//    public static synchronized SingletonSynchronized getInstance(){
//        synchronized (SingletonSynchronized.class){
//            if (null == singleton){
//                singleton = new SingletonSynchronized();
//            }
//        }
//        return singleton;
//    }

}
  • getInstance方法上進行加鎖之後, 在多執行緒的情況下就能保證單例的正確性了, 但是每次呼叫getInstance方法都有進行獲取鎖和釋放鎖的操作, 對效能是由一定影響的
  • 不過synchronized的效能並沒有想象中的那麼差, 是因為在jdk1.6之後, 對synchronized進行了很多優化, 引入了偏向鎖和輕量級鎖的概念, 詳細情況這裡就不多說了, 想了解的可以參考這篇文章:https://blog.csdn.net/love905661433/article/details/82871531
  • 繼續說回到設計模式, 對於這種情況, 引入了雙重檢查的單例模式
    3. 雙重檢查的單例模式程式碼如下 :
/**
 * 單例模式 : 雙重檢查
 * 防止併發情況下問題
 * @author 七夜雪
 * 2018/11/14 17:26
 */
public class SingletonDoubleCheck {
    private static SingletonDoubleCheck singleton;

    private SingletonDoubleCheck() {
    }

    public static SingletonDoubleCheck getInstance(){
        if (null == singleton){
        	// 加鎖保證這個程式碼塊只有一個執行緒能夠執行
            synchronized (SingletonDoubleCheck.class){
            	// 避免在獲取鎖的過程中, 物件被其他執行緒建立, 所以再進行一次檢查
                if (null == singleton) {
                    singleton = new SingletonDoubleCheck();
                }
            }
        }

        return singleton;
    }
}
  • 通過兩次null == singleton判斷, 既保證了反覆加鎖的問題, 又保證了多執行緒情況下單例模式能夠正常工作
    看到這裡是不是都絕對這個方案已經完美解決了併發安全性以及效能問題呢, 事實上這個程式碼仍然是由問題的, 在多執行緒情況下, 仍然存在風險, 為什麼會存在風險呢? 這是因為在jvm中, 存在指令重排序現象, 下面我們具體來進行分析一下 :
  • singleton = new SingletonDoubleCheck();首先這行看起來只有一句, 但其實是分成了三條指令進行執行的 :
  1. 分配記憶體給這個物件
  2. 初始化物件
  3. 設定singleton指向剛剛分配的記憶體地址
  • 但是對於上面的情況, 2和3可能會被重排序, 執行順序有可能是1->2->3, 也有可能是1->3->2, 因為jvm規範中只要求單執行緒情況下這種情況能夠獲得正確的結果
  • 如果執行順序是1->3->2的順序的話, 執行了第三步之後, 這個時候singleton就已經不為null了, 這是如果第二個執行緒進入的話, 判斷髮現singleton不為null, 直接返回的話, 就會出現問題, 因為這時singleton物件並沒有初始化完成, 具體參見下圖
    單執行緒情況 :
    在這裡插入圖片描述
    併發情況 :
    在這裡插入圖片描述
    可以看出在併發情況下, 執行緒1有可能會被訪問到並沒有初始化完成的物件

通過上面的分析可以知道, 上面的這種double check的單例模式仍然是存在問題, 那這個問題該如何解決呢?
4. 事實上解決上面的這個問題非常簡單, 只需要修改一行程式碼 :

只需要對這一行宣告private static SingletonDoubleCheck singleton;
增加一個volatile關鍵字即可 : private static volatile SingletonDoubleCheck singleton;
為何增加一個volatile就能解決這個問題呢, 簡單來說就是volatile可以禁止2, 3兩步進行指令重排序, 具體更多關於volatile的資訊可以參考 : https://blog.csdn.net/love905661433/article/details/82833361

除了上面的volatile關鍵字之外, 還有第二種方式解決指令重排序造成的執行緒安全問題 :

/**
 * 基於靜態內部類的單例模式
 *
 * @author 七夜雪
 * @create 2018-11-22 20:57
 */
public class StaticInnerClassSingleton {
    // 注意私有的構造方法
    private StaticInnerClassSingleton(){

    }

    public StaticInnerClassSingleton getInstance(){
        return InnerClass.instance;
    }

    private static class InnerClass{
        private static StaticInnerClassSingleton instance = new StaticInnerClassSingleton();
    }

}

為何使用這種靜態內部類的方式就能解決指令重排序問題呢, 這是因為jvm在進行Class物件初始化的時候, 會增加Class物件的初始化鎖, 所以哪個物件能夠拿到靜態內部類的初始化鎖, 哪個物件就能完成對靜態內部類的初始化, 所以即使存在指令重排序, 也不影響執行緒安全性問題, 如下圖:

在這裡插入圖片描述
關於Class類的初始化問題, 這裡提一下, 在發生下面幾種情況下, 會對Class類進行初始化:

  • 例項化一個類,new一個類的例項物件
  • 訪問類的靜態變數
  • 呼叫類的靜態方法
  • 通過反射呼叫類
  • 例項化類的子類
  • 被標位啟動類的類

餓漢式

  1. 首先仍然是看下最簡單的餓漢式單例模式寫法:
/**
 * 單例模式 : 餓漢模式
 * @author 七夜雪
 * 2018/11/14 17:13
 */
public class Singleton {
    private final static Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }

    private Singleton() {
    }
}
  • 上面這種惡漢式的寫法很簡單, 就是在Class類載入的時候, 完成instance物件的建立, 所以不存在任何執行緒安全問題
  • 唯一的問題就是, 不管這個單例物件有沒有用到, 在類載入完成之後這個物件就已經被建立成功了, 會造成一定的記憶體浪費, 如果這個物件很小的話, 這種影響並不大, 也可以將初始化放在靜態程式碼塊中, 效果是一樣的, 程式碼如下:
/**
 * 單例模式 : 靜態程式碼塊餓漢模式
 *
 * @author 七夜雪
 * 2018/11/14 17:13
 */
public class StaticHungrySingleton {
    private static StaticHungrySingleton instance;

    static {
        instance = new StaticHungrySingleton();
    }

    public static StaticHungrySingleton getInstance() {
        return instance;
    }

    private StaticHungrySingleton() {
    }
}

單例模式安全性問題

是不是經過上面一系列優化之後, 覺得單例模式已經不存在安全性問題了, 事實上單例模式仍然可以被破壞, 下面來繼續看

序列化破壞單例

以餓漢式單例為例, 單例程式碼如下:

/**
 * 單例模式 : 餓漢模式
 * @author 七夜雪
 * 2018/11/14 17:13
 */
public class Singleton implements Serializable {
    private static Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }

    private Singleton() {
    }
}

上面的單例的程式碼實現了一個序列化介面, 避免序列化的時候報錯, 下面我們來使用序列化的方式來測試一下序列化是不是能破壞單例, 程式碼如下:

/**
 * 破壞單例模式的測試
 *
 * @author 七夜雪
 * @create 2018-11-22 21:51
 */
public class DestroySingletonTest {

    /**
     * 使用序列化方式破壞單例
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        Singleton instance = Singleton.getInstance();
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("sinleton.dat"));
        oos.writeObject(instance);
        oos.close();
        File file = new File("sinleton.dat");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        Singleton newInstance = (Singleton) ois.readObject();
        System.out.println(instance);
        System.out.println(newInstance);
        System.out.println(instance == newInstance);
    }

}

輸出結果:

[email protected]
[email protected]
false

從輸出結果可以看出, 序列化之後再進行反序列化的話, 得到的就不是同一個物件了, 這就破壞了單例模式的單例特性, 那應該如何解決這個問題呢, 解決的方法也很簡單, 在Singleton類中加入一個readResolve()方法即可, 增加之後Singleton類程式碼如下:

import java.io.Serializable;

/**
 * 單例模式 : 餓漢模式
 * @author 七夜雪
 * 2018/11/14 17:13
 */
public class Singleton implements Serializable {
    private static Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }

    private Singleton() {
    }

    public Object readResolve(){
        return instance;
    }
}

然後增加了readResolve方法之後, 再執行一次上面的測試類, 結果如下:

[email protected]
[email protected]
true

發現反序列化對單例的破壞已經解決了, 為什麼加了readResolve方法之後就可以了呢, 我們來看下jdk的原始碼 :

  1. 首先來看下ObjectInputStream的readObject方法, 程式碼如下:
public final Object readObject()
        throws IOException, ClassNotFoundException
    {
        if (enableOverride) {
            return readObjectOverride();
        }

        // if nested read, passHandle contains handle of enclosing object
        int outerHandle = passHandle;
        try {
            Object obj = readObject0(false);
//  ......................看到這個readObject0方法即可,下面的部分省略了........................
  1. readObject0方法原始碼如下:
/**
     * Underlying readObject implementation.
     */
    private Object readObject0(boolean unshared) throws IOException {
    // ..............無關緊要的程式碼這裡省略了.................
        byte tc;
        while ((tc = bin.peekByte()) == TC_RESET) {
            bin.readByte();
            handleReset();
        }

        depth++;
        totalObjectRefs++;
        try {
            switch (tc) {
    // ..............其他case省略, 這裡是Object型別.................			
                case TC_OBJECT:
                    // checkResolve方法和readOrdinaryObject就是處理這個問題的
                    return checkResolve(readOrdinaryObject(unshared));
 // ..............已經找到關鍵程式碼了, 下面的程式碼這裡就省略了.................                   

  1. 繼續看readOrdinaryObject的方法
    private Object readOrdinaryObject(boolean unshared)
        throws IOException
    {
// ....................篇幅有限,這裡只儲存關鍵程式碼.........................
        ObjectStreamClass desc = readClassDesc(false);
        Object obj;
        // hasReadResolveMethod這個就是判斷原來的Singleton中是否有readResolve方法的, 這裡是根據方法名判斷的, 所以Singleton中方法名就只能是readResolve
        //有這麼一行程式碼 readResolveMethod = getInheritableMethod(cl, "readResolve", null, Object.class);
        if (obj != null &&
            handles.lookupException(passHandle) == null &&
            desc.hasReadResolveMethod())
        {
        	// 這裡就是重點了, 如果存在readResolve方法, 就通過反射呼叫readResolve方法返回
            Object rep = desc.invokeReadResolve(obj);
            if (unshared && rep.getClass().isArray()) {
                rep = cloneArray(rep);
            }
            if (rep != obj) {
                // Filter the replacement object
                if (rep != null) {
                    if (rep.getClass().isArray()) {
                        filterCheck(rep.getClass(), Array.getLength(rep));
                    } else {
                        filterCheck(rep.getClass(), -1);
                    }
                }
                handles.setObject(passHandle, obj = rep);
            }
        }

        return obj;
    }
  1. checkResolve方法其實沒啥好說的, 就是把readOrdinaryObject方法返回的物件返回出去

通過原始碼的分析, 可以指定為啥加了readResolve方法就可以解決序列化反序列化的問題了

通過反射破壞單例特性

同樣的, 以上面的Singleton程式碼為例, 來試一下通過反射能不能破壞單例的特性, 反射的測試程式碼如下:

    /**
     * 使用反射方式破壞單例
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        Singleton instance = Singleton.getInstance();
        Class clazz = Singleton.class;
        // 獲取構造方法
        Constructor constructor = clazz.getDeclaredConstructor();
        // 由於構造方法是私有的, 所以這裡先開放許可權
        constructor.setAccessible(true);
        Singleton newInstance = (Singleton) constructor.newInstance();
        System.out.println(instance);
        System.out.println(newInstance);
        System.out.println(instance == newInstance);
    }

輸出結果:

[email protected]
[email protected]
false

從輸出結果可以看出, 通過反射,確實破壞了單例的特性, 那麼如何解決這個問題呢, 可以在構造器中增加一個判斷, 程式碼如下:

/**
 * 單例模式 : 餓漢模式
 * @author 七夜雪
 * 2018/11/14 17:13
 */
public class Singleton implements Serializable {
    private static Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }

    private Singleton() {
        // 防止反射破壞單例
        if (instance != null) {
            throw new RuntimeException("單例構造器不允許反射呼叫");
        }
    }

    /**
     * 防止序列化破壞單例
     * @return
     */
    public Object readResolve(){
        return instance;
    }
}

再次執行反射的測試程式碼, 得到如下結果:

Exception in thread “main” java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at pattern.creational.singleton.DestroySingletonTest.main(DestroySingletonTest.java:26)
Caused by: java.lang.RuntimeException: 單例構造器不允許反射呼叫
at pattern.creational.singleton.Singleton.(Singleton.java:19)
… 5 more

從結果可以看到, 現在就無法通過反射來破壞單例的特性了, 加了上面的判斷之後, 保證了構造器只能執行一次, 而餓漢式的單例模式在類載入的時候, 物件就已經建立了, 所以可以通過這個方式來處理反射的問題, 但是如果使用懶漢模式的話, 就無法避免反射呼叫的問題了, 因為沒有辦法區分第一次呼叫構造方法是通過反射呼叫的, 還是通過getInstance方法觸發的, 所以就沒辦法通過這個方式解決了

列舉Enum實現單例模式

  • 列舉可能是實現單例的最佳實踐
  • 使用列舉實現單例的程式碼如下:
/**
 * @author 七夜雪
 * 使用列舉實現單例
 * @create 2018-11-23 0:11
 */
public enum EnumSingleton {
    INSTANCE;

    private Object data;

    public static EnumSingleton getInstance(){
        return INSTANCE;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

測試程式碼 :

    /**
     * 使用序列化方式破壞單例
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        System.out.println("----------測試序列化方法對單例的破壞----------");
        EnumSingleton instance = EnumSingleton.getInstance();
        // 同時設定一個Object物件, 看下反序列化之後有沒有被破壞
        instance.setData(new Object());
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("sinleton.dat"));
        oos.writeObject(instance);
        File file = new File("sinleton.dat");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        EnumSingleton newInstance = (EnumSingleton) ois.readObject();
        System.out.println(instance);
        System.out.println(newInstance);
        System.out.println(instance == newInstance);
        System.out.println(instance.getData() == newInstance.getData());
    }

輸出結果:

----------測試序列化方法對單例的破壞----------
INSTANCE
INSTANCE
true
true

下面測試一下使用反射破壞單例模式, 測試程式碼如下:

    /**
     * 使用序列化方式破壞單例
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        System.out.println("----------測試序列化方法對單例的破壞----------");
        EnumSingleton instance = EnumSingleton.getInstance();
        Constructor constructor = EnumSingleton.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        EnumSingleton newInstance = (EnumSingleton) constructor.newInstance();
        System.out.println(instance);
        System.out.println(newInstance);
        System.out.println(instance == newInstance);
    }

輸出結果:

Exception in thread “main” java.lang.NoSuchMethodException: pattern.creational.singleton.EnumSingleton.()
----------測試序列化方法對單例的破壞----------
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.getDeclaredConstructor(Class.java:2178)
at pattern.creational.singleton.EnumTest.main(EnumTest.java:43)

執行上面的測試程式, 拋了個異常, 是沒找到無參的構造方法, 對生成的class進行反編譯之後發現, 只有如下構造方法:

    private EnumSingleton(String s, int i)
    {
        super(s, i);
    }

那下面修改一下測試程式碼, 再進行一次測試, 修改後測試程式碼如下:

    /**
     * 使用序列化方式破壞單例
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        System.out.println("----------測試序列化方法對單例的破壞----------");
        EnumSingleton instance = EnumSingleton.getInstance();
        Constructor constructor = EnumSingleton.class.getDeclaredConstructor(String.class, int.class);
        constructor.setAccessible(true);
        EnumSingleton newInstance = (EnumSingleton) constructor.newInstance();
        System.out.println(instance);
        System.out.println(newInstance);
        System.out.println(instance == newInstance);
    }

再次執行測試程式碼, 輸出結果如下 :

----------測試序列化方法對單例的破壞----------
Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
	at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
	at pattern.creational.singleton.EnumTest.main(EnumTest.java:45)

發現通過反射呼叫的話, 依然會拋一個異常, 所以使用Enum來實現單例是安全的, 通過序列化和反射都無法破壞其單例特性

我們從JDK原始碼來看下, 為什麼Enum具有這些特徵
1. 首先看下為什麼反射無法建立列舉型別的類, 看下newInstance原始碼, 原始碼中有下面這一句:

        if ((clazz.getModifiers() & Modifier.ENUM
            
           

相關推薦

設計模式-模式(Singleton)

概述 定義 : 保證一個類僅有一個例項, 並提供一個全域性訪問點 又稱單件模式 型別 : 建立型 適用場景 想確保任何情況下都絕對只有一個例項 優點 在記憶體裡只有一個例項, 減少了記憶體開銷 可以避免對資源的多重

設計模式 - 模式)看看和你理解的是否一樣?

一、概述 單例模式是設計模式中相對簡單且非常常見的一種設計模式,但是同時也是非常經典的高頻面試題,相信還是有很多人在面試時會掛在這裡。本篇文章主要針對單例模式做一個回顧,記錄單例模式的應用場景、常見寫法、針對執行緒安全進行除錯(看得見的執行緒)以及總結。相信大家看完這篇文章之後,對單例模式有一個非常深刻的認識

設計模式-Singleton

don 設計模式 static sha 應用 ces zed void 內部類 2018-1-12 by Atlas UML UML中加“-”表示私有的(private); UML中加“+”表示公有的(public); UML中加“_”表示靜態的(static)

JAVA設計模式-模式(Singleton)線程安全與效率

保存 ring 使用方法 部分 rac cheng 原因 cts 要求 一,前言   單例模式詳細大家都已經非常熟悉了,在文章單例模式的八種寫法比較中,對單例模式的概念以及使用場景都做了很不錯的說明。請在閱讀本文之前,閱讀一下這篇文章,因為本文就是按照這篇文章中的八種單例模

設計模式01 建立型模式 - 模式(Singleton Pattern)

參考 [1] 設計模式之:建立型設計模式(6種) | 部落格園 [2] 單例模式的八種寫法比較 | 部落格園   單例模式(Singleton  Pattern) 確保一個類有且僅有一個例項,並且為客戶提供一個全域性訪問點。   特點 1) 保證被訪問資

用心理解設計模式——模式 (Singleton Pattern)

前置文章: 用心理解設計模式——設計模式的原則  設計模式相關程式碼已統一放至 我的 Github   一、定義   建立型模式之一。   Ensure a class has only one instance, an

設計模式-模式 Singleton

1 好處 1、 避免例項物件的重複建立,節約記憶體空間 2、 能夠避免由於操作多個例項導致的邏輯錯誤 例子 1、 正常的new物件 Singleton ns = new Singleton(); System.out.println("-

JAVA設計模式-模式(Singleton)執行緒安全與效率

一,前言   單例模式詳細大家都已經非常熟悉了,在文章單例模式的八種寫法比較中,對單例模式的概念以及使用場景都做了很不錯的說明。請在閱讀本文之前,閱讀一下這篇文章,因為本文就是按照這篇文章中的八種單例模式進行探索的。   本文的目的是:結合文章中的八種單例模式的寫法,使用實際的示例,來演示執行緒安全和效率  

設計模式 - 模式(singleton pattern)

設計模式 - 單例模式(singleton pattern) 餓漢模式 public class Singleton{ private static final Singleton singleton = new Singleton (); private

設計模式-模式(Singleton)

單例模式 定義: 一個類有且僅有一個例項,並且自行例項化向整個系統提供 要點: 某個類只能有一個例項(類只提供私有的建構函式) 它必須自行建立這個例項(類定義中含有一個該類的靜態私有物件) 它必須自行向整個系統提供這個例項(該類提供了一個靜態的公有的函式用

設計模式-模式Singleton

單例物件(Singleton)是一種常用的設計模式。在Java應用中,單例物件能保證在一個JVM中,該物件只有一個例項存在。我們常把單例模式分兩種:飢漢模式和飽含模式。 1、飢漢模式 public class Singleton {          private st

設計模式-模式(Singleton)各種寫法和分析比較

介紹 單例模式是設計模式中比較簡單容易理解的。它的出現主要是: 保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點 其實就在系統執行期間中保證只有這麼一個例項,並能夠全域性訪問。應用場景就是當需要一個物件時,這個物件需要整個系統執行期間只有一個,並且這個物件的

設計模式-模式(Singleton)在Android中的應用場景和實際使用遇到的問題

介紹 在上篇部落格中詳細說明了各種單例的寫法和問題。這篇主要介紹單例在Android開發中的各種應用場景以及和靜態類方法的對比考慮,舉實際例子說明。 單例的思考 寫了這麼多單例,都快忘記我們到底為什麼需要單例,複習單例的本質 單例的本質:控制例

設計模式--模式Singleton

........................................單例模式.............................................. 單例模式:即唯一

設計模式模式Singleton

一、什麼是單例模式: 單例(Singleton)模式是一種常用的建立型設計模式。 簡單來說就是一個類只能構建一個物件的設計模式。 核心作用:保證一個類只有一個例項,並且提供一個訪問該例項的全域性訪問點。 二、單例模式的應用場景: 1、需要生成唯一序列的環境

[轉]設計模式--模式(一)懶漢式和餓漢式

打印 是否 調用構造 餓漢 一段 tools 會有 輸出結果 java 單例模式是設計模式中比較簡單的一種。適合於一個類只有一個實例的情況,比如窗口管理器,打印緩沖池和文件系統, 它們都是原型的例子。典型的情況是,那些對象的類型被遍及一個軟件系統的不同對象訪問,因此需要一個

javascript設計模式-模式

空間 spa 靜態變量 通過 script 無法 單例 onf 訪問 單例模式,是創建型設計模式的一種,又被稱為單體模式,是只允許實例化一次的對象類。有時也用來規劃一個命名空間。 1 var Util = { 2 getName: function () {

設計模式--模式

final 簡單 封裝 產生 非線程安全 span 操作 ati zed 單例設計模式 Singleton是一種創建型模式,指某個類采用Singleton模式,則在這個類被創建後,只可能產生一個實例供外部訪問,並且提供一個全局的訪問點。 核心知識點如下: (1) 將采用單例

設計模式——模式

pre hostname turn cin user order 總結 -type path_info 單例模式 實例:web應用程序 #!/usr/bin/env python #coding:utf-8 from wsgiref.simple_server impor

設計模式-模式

java return 全局對象 實例化 urn ole col scrip 獨立   單例,即一個對象只有一個實例,即使實例化多次,拿到的也是同一個實例。   JavaScript中,全局對象就是單例,如:window、document;獲取的DOM也是單例的。   單例