設計模式之單例模式-Singleton

Singleton單類模式是最簡單的設計模式,它的主要作用是保證在程序運行生命週期中,使用了單類模式的類只能有一個實例對象存在。單類模式實現了類似C語言中全局變量的功能,單類模式常用於註冊/查找的服務。

單類模式的UML圖如下:


單類模式有兩種實現方式:飽漢模式和餓漢模式,如下:

1.飽漢單類模式例子代碼:

  1. public class Singleton1{  
  2.         //飽漢模式,聲明時就創建實例對象  
  3.     public static final Singleton1 instance = new Singleton1();  
  4.     //單類模式的構造方法必須爲private,以避免通過構造方法創建對象實例,  
  5.         //並且必須顯示聲明構造方法,以防止使用默認構造方法  
  6.     private Singleton1(){}  
  7.         //單類模式必須對外提供獲取實例對象的方法  
  8.         public static Singleton1 geInstance(){  
  9.            return instance;  
  10.         }  
  11. }  

2.餓漢單類模式即延遲初始化單類方式,例子代碼:

  1. public class Singleton2{  
  2.         //餓漢模式,聲明時不創建實例對象  
  3.     public static Singleton2 instance;  
  4.     //單類模式的構造方法必須爲private,以避免通過構造方法創建對象實例,  
  5.         //並且必須顯示聲明構造方法,以防止使用默認構造方法  
  6.     private Singleton2(){}  
  7.         //單類模式必須對外提供獲取實例對象的方法,延遲初始化的單類模式必須使用synchronized同步關鍵字,否則多線程情況下很容易產生多個實例對象  
  8.         public static synchronized Singleton2 geInstance(){  
  9.            //延遲初始化,只有當第一次使用時才創建對象實例  
  10.            if(instance == null){  
  11.                return new Singleton2();  
  12.                 }  
  13.                return instance;  
  14.         }  
  15. }  

一般認爲飽漢模式要比餓漢模式更加安全。

上面兩種Singleton單類設計模式的實現方式都隱藏有如下的問題:

(1).雖然構造方式的訪問修飾符爲private,即除了自身以外其他任何類都無法調用,但是通過反射機制的setAccessiable(true)方法可以訪問私有方法和屬性。因此Singleton單類模式必須考慮這種例外情況。

(2).對象序列化之後再反序列化時會生成新的對象,因此當Singleton單類模式類實現序列化接口時,必須顯式聲明所有的字段爲tranisent,並且提供如下的readResolve方法來防止通過序列化破壞單態模式:

  1. private Object readResolve(){  
  2.     return INSTANCE;  
  3. }  

3.使用Lazy initialization holder class模式實現單態:

  1. public class Singleton3 {    
  2.    /**  
  3.     * 類級的內部類,也就是靜態的成員式內部類,該內部類的實例與外部類的實例  
  4.     * 沒有綁定關係,而且只有被調用到纔會裝載,從而實現了延遲加載  
  5.     */    
  6.    private static class SingletonHolder{    
  7.        /**  
  8.         * 靜態初始化器,由JVM來保證線程安全  
  9.         */    
  10.        private static Singleton3 instance = new Singleton3();    
  11.    }    
  12.    /**  
  13.     * 私有化構造方法  
  14.     */    
  15.    private Singleton3(){    
  16.    }    
  17.    public static  Singleton3 getInstance(){    
  18.        return SingletonHolder.instance;    
  19.    }    
當getInstance方法第一次被調用的時候,它第一次讀取SingletonHolder.instance,導致SingletonHolder類得到初始化;而這個類在裝載並被初始化的時候,會初始化它的靜態域,從而創建Singleton的實例,由於是靜態的域,因此只會被虛擬機在裝載類的時候初始化一次,並由虛擬機來保證它的線程安全性。
這個模式的優勢在於,getInstance方法並沒有被同步,並且只是執行一個域的訪問,因此延遲初始化並沒有增加任何訪問成本。

4.在JDK1.5之後引入了Enum枚舉,因此在JDK1.5之後Singleton單類模式又有了第三種實現方式,也是最好的實現方式,例子如下:

  1. public enum Singleton4{  
  2.     INSTANCE{  
  3.         public void doSomething(){  
  4.             ……  
  5.         }  
  6.     };  
  7.     public abstract void doSomething();    
  8. }  
Singleton單類模式中只有一個INSTANCE枚舉元素,枚舉可以保證真個程序生命週期中只有一個實例對象存在,同時還避免了常規Singleton單類模式private構造方法被反射調用和序列化問題(枚舉提供了序列化保證機制,確保多次序列化和反序列化不會創建多個實例對象)。

注意:java中除了構造方法可以創建對象實例以外,還可以通過克隆方法(clone()是Object中的protected方法)來創建對象,若單類對象直接繼承自Object對象,則如果沒有提供具體clone方法實現,則當調用克隆方法創建對象時,會拋出運行時的異常CloneNotSupportedException。

若單類類繼承了實現克隆方法的類,則在單類類中必須覆蓋父類的克隆方法,顯式拋出異常CloneNotSupportedException。

另外,實現了單類模式的類不能再有派生子類,因爲構造方式是私有的,子類無法調用父類構造方法,因此達到了Final的效果。

JDK的中單態模式的應用:

java.lang.Runtime

轉自:點擊打開鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章