Singleton單類模式是最簡單的設計模式,它的主要作用是保證在程序運行生命週期中,使用了單類模式的類只能有一個實例對象存在。
單類模式有兩種實現方式:飽漢模式和餓漢模式,如下:
飽漢單例模式
public class Singleton1{
//飽漢模式,聲明時就創建實例對象
public static final Singleton1 instance = new Singleton1();
//單類模式的構造方法必須爲private,以避免通過構造方法創建對象實例,
//並且必須顯示聲明構造方法,以防止使用默認構造方法
private Singleton1(){}
//單類模式必須對外提供獲取實例對象的方法
public static Singleton1 geInstance(){
return instance;
}
}
餓漢單例模式
public class Singleton2{
//餓漢模式,聲明時不創建實例對象
public static Singleton2 instance;
//單類模式的構造方法必須爲private,以避免通過構造方法創建對象實例,
//並且必須顯示聲明構造方法,以防止使用默認構造方法
private Singleton2(){}
//單類模式必須對外提供獲取實例對象的方法,延遲初始化的單類模式必須使用synchronized同步關鍵字,否則多線程情況下很容易產生多個實例對象
public static synchronized Singleton2 geInstance(){
//延遲初始化,只有當第一次使用時才創建對象實例
if(instance == null){
return new Singleton2();
}
return instance;
}
}
一般認爲飽漢模式要比餓漢模式更加安全。
上面兩種Singleton單類設計模式的實現方式都隱藏有如下的問題:
(1).雖然構造方式的訪問修飾符爲private,即除了自身以外其他任何類都無法調用,但是通過反射機制的setAccessiable(true)方法可以訪問私有方法和屬性。因此Singleton單類模式必須考慮這種例外情況。
(2).對象序列化之後再反序列化時會生成新的對象,因此當Singleton單類模式類實現序列化接口時,必須顯式聲明所有的字段爲tranisent,並且提供如下的readResolve方法來防止通過序列化破壞單態模式:
3.使用Lazy initialization holder class模式實現單態:
public class Singleton3 {
/**
* 類級的內部類,也就是靜態的成員式內部類,該內部類的實例與外部類的實例
* 沒有綁定關係,而且只有被調用到纔會裝載,從而實現了延遲加載
*/
private static class SingletonHolder{
/**
* 靜態初始化器,由JVM來保證線程安全
*/
private static Singleton3 instance = new Singleton3();
}
/**
* 私有化構造方法
*/
private Singleton3(){
}
public static Singleton3 getInstance(){
return SingletonHolder.instance;
}
}
當getInstance方法第一次被調用的時候,它第一次讀取SingletonHolder.instance,導致SingletonHolder類得到初始化;而這個類在裝載並被初始化的時候,會初始化它的靜態域,從而創建Singleton的實例,由於是靜態的域,因此只會被虛擬機在裝載類的時候初始化一次,並由虛擬機來保證它的線程安全性。
這個模式的優勢在於,getInstance方法並沒有被同步,並且只是執行一個域的訪問,因此延遲初始化並沒有增加任何訪問成本。
public enum Singleton4{
INSTANCE{
public void doSomething(){
……
}
};
public abstract void doSomething();
}
Singleton單類模式中只有一個INSTANCE枚舉元素,枚舉可以保證真個程序生命週期中只有一個實例對象存在,同時還避免了常規Singleton單類模式private構造方法被反射調用和序列化問題(枚舉提供了序列化保證機制,確保多次序列化和反序列化不會創建多個實例對象)。
注意:java中除了構造方法可以創建對象實例以外,還可以通過克隆方法(clone()是Object中的protected方法)來創建對象,若單類對象直接繼承自Object對象,則如果沒有提供具體clone方法實現,則當調用克隆方法創建對象時,會拋出運行時的異常CloneNotSupportedException。
若單類類繼承了實現克隆方法的類,則在單類類中必須覆蓋父類的克隆方法,顯式拋出異常CloneNotSupportedException。
另外,實現了單類模式的類不能再有派生子類,因爲構造方式是私有的,子類無法調用父類構造方法,因此達到了Final的效果。