1. 程式人生 > >Head First設計模式總結(五) 單件模式

Head First設計模式總結(五) 單件模式

本文基於《Head First 設計模式》一書,對單件模式進行了概括和總結

單件模式確保一個類只有一個例項,並提供一個全域性訪問點 有一些物件我們只需要一個,比方說:執行緒池(threadpool)、快取(cache)、對話方塊、處理偏好設定和登錄檔(registry)的物件、日誌物件,充當印表機、顯示卡等裝置的驅動程式的物件。事實上,這類物件只能有一個例項,如果製造出多個例項,就會導致許多問題產生,例如:程式的異常行為、資源使用過量,或者是不一致的結果。

建立單件模式的步驟如下:

步驟 1

建立一個SingleObject類

public class SingleObject {
 
   //建立 SingleObject 的一個物件
   private static SingleObject instance = new SingleObject();
 
   //讓建構函式為 private,這樣該類就不會被例項化
   private SingleObject(){}
 
   //獲取唯一可用的物件
   public static SingleObject getInstance(){
      return instance;
   }
 
   public void showMessage(){
      System.out.println("Hello World!");
   }
}
步驟 2

從Singleton類獲取唯一的物件

public class SingletonPatternDemo {
   public static void main(String[] args) {
      //不合法的建構函式
      //編譯時錯誤:建構函式 SingleObject() 是不可見的
      //SingleObject object = new SingleObject();
 
      //獲取唯一可用的物件
      SingleObject object = SingleObject.getInstance();
 
      //顯示訊息
      object.showMessage();
   }
}
步驟 3

執行程式,得到結果 Hello World!

下面給出幾種特殊情況下的單件模式

1、懶漢式 (同步getInstance方法) (執行緒不安全)

特點:這種方式是最基本的實現方式,這種實現最大的問題就是不支援多執行緒。因為沒有加鎖 synchronized,所以嚴格意義上它並不算單例模式。 這種方式 lazy loading 很明顯,不要求執行緒安全,在多執行緒下不能正常工作。

public class Singleton{
        private static Singleton uniqueInstance ;
        private Singleton(){}
        public static synchronized Singleton getInstance(){  //同步解決了多執行緒的安全問題,但效能變差
            if(uniqueInstance == null){    //懶漢式,當要用時才例項化變數
                uniqueInstance = new Singleton();
            }
            return uniqueInstance;
        }
    }

//同步會降低程式的效能,同步一個方法可能會使程式的執行效率下降100倍,當getInstance方法在不頻繁的地方使用時,可以同步該方法。

2、急切例項化(執行緒安全) 特點:這種方式比較常用,但容易產生垃圾物件。優點是沒有加鎖,執行效率高,缺點是類載入時就初始化了,浪費記憶體。

public class Singleton{
    private static Singleton uniqueInstance = new Singleton();//保證了執行緒安全
    private Singleton(){}
    public static Singleton getInstance(){
        return uniqueInstance;
    }
}

3、雙重檢查加鎖 (若效能為關注的重點,那麼這個方法可以提高程式效能,該方法不適用於java1.4及更早的版本)

public class Singleton{
        private static volatile Singleton uniqueInstance;
        private Singleton(){}
        public static Singleton getInstance(){
            if(uniqueInstance == null){
                synchronized(Singleton.class){
                    if(uniqueInstance == null){
                        uniqueInstance = new Singleton();
                    }
                }
            }
            return uniqueInstance;
        }
    }
    //volatile關鍵字確保:當uniqueInstance變數被初始化為Singleton例項時,多個執行緒能正確的處理uniqueInstance變數。

4、登記式(靜態內部類) 特點:這種方式能達到雙檢鎖方式一樣的功效,但實現更簡單。對靜態域使用延遲初始化,應使用這種方式而不是雙檢鎖方式。這種方式只適用於靜態域的情況,雙檢鎖方式可在例項域需要延遲初始化時使用。

public class Singleton {  
    private static class SingletonHolder {  
    private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
    return SingletonHolder.INSTANCE;  
    }  
}

5、列舉 特點:這種實現方式還沒有被廣泛採用,但這是實現單例模式的最佳方法。它更簡潔,自動支援序列化機制,絕對防止多次例項化。

public enum Singleton {  
    INSTANCE;  
    public void whateverMethod() {  
    }  
}