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

設計模式之---單例模式(Singleton Pattern)

基本概念

  確保某一個類只有一個例項,而且自行例項化並向整個系統提供這個例項,這個類稱為單例類,它提供全域性訪問的方法。單例模式是一種建立型模式。

緣起

  某些類,我們希望在程式執行期間有且只有一個例項,原因可能是該類的建立需要消耗系統過多的資源、花費很多的時間,或者業務上客觀就要求了只能有一個例項。

特點

  1. 單例類只能有一個例項。
  2. 單例類必須自己建立自己的唯一例項。
  3. 單例類必須給所有其他物件提供這一例項。

應用場景

  1. 系統只需要一個例項物件,如系統要求提供一個唯一的序列號生成器或資源管理器,或者需要考慮資源消耗太大而只允許建立一個物件。
  2. 客戶呼叫類的單個例項只允許使用一個公共訪問點,除了該公共訪問點,不能通過其他途徑訪問該例項。

常見應用

  1. 配置檔案
  2. 日曆類
  3. IOC容器
  4. Windows工作管理員
  5. IOC容器級別的單例bean

常見的幾種實現方式

餓漢式單例

public class EagerSingleton {   
    private static final EagerSingleton instance = new EagerSingleton();   
    private EagerSingleton() { }   
    public static EagerSingleton getInstance() {  
        return instance;   
    }     
}

優點:
執行緒安全、在類載入的同時已經建立好一個靜態物件,呼叫時反應速度快

缺點:
資源效率不高,類載入時就初始化,浪費記憶體。可能getInstance()永遠不會執行到,但執行該類的其他靜態方法或者載入了該類(class.forName),那麼這個例項仍然初始化

懶漢式單例

public class LazySingleton {   
    private volatile static LazySingleton instance = null;

    private LazySingleton() { }   

    public
static LazySingleton getInstance() { //第一重判斷 if (instance == null) { //鎖定程式碼塊 synchronized (LazySingleton.class) { //第二重判斷 if (instance == null) { instance = new LazySingleton(); //建立單例例項 } } } return instance; } }

優點:
資源利用率高,不執行getInstance()就不被例項,可以執行該類其他靜態方法

缺點 :
第一次載入時反應不快,由於java記憶體模型一些原因偶爾失敗

內部靜態類實現

public class Singleton {  
    private Singleton() {  
    }  

    private static class SingletonHolder {  
        private final static Singleton instance = new Singleton();  
    }  

    public static Singleton getInstance() {  
        return SingletonHolder.instance;  
    }    
}  

優點:
資源利用率高,不執行getInstance()不被例項,可以執行該類其他靜態方法

缺點 :
第一次載入時反應不夠快

列舉實現

public enum EnumSingleton {
  INSTANCE;
}

優點:
程式碼簡潔,執行緒安全,防反射攻擊、防止序列化生成新的例項

缺點:
不支援java1.5以下

單例模式總結

一.主要優點

  1. 單例模式提供了對唯一例項的受控訪問。因為單例類封裝了它的唯一例項,所以它可以嚴格控制客戶怎樣以及何時訪問它。
  2. 由於在系統記憶體中只存在一個物件,因此可以節約系統資源,對於一些需要頻繁建立和銷燬的物件單例模式無疑可以提高系統的效能。
  3. 允許可變數目的例項。基於單例模式我們可以進行擴充套件,使用與單例控制相似的方法來獲得指定個數的物件例項,既節省系統資源,又解決了單例物件共享過多有損效能的問題。

二.主要缺點

  1. 由於單例模式中沒有抽象層,因此單例類的擴充套件有很大的困難。
  2. 單例類的職責過重,在一定程度上違背了“單一職責原則”。因為單例類既充當了工廠角色,提供了工廠方法,同時又充當了產品角色,包含一些業務方法,將產品的建立和產品的本身的功能融合到一起。
  3. 現在很多面向物件語言(如Java、C#)的執行環境都提供了自動垃圾回收的技術,因此,如果例項化的共享物件長時間不被利用,系統會認為它是垃圾,會自動銷燬並回收資源,下次利用時又將重新例項化,這將導致共享的單例物件狀態的丟失。