Singleton單類模式是最簡單的設計模式,它的主要作用是保證在程序運行生命週期中,使用了單類模式的類只能有一個實例對象存在。單類模式實現了類似C語言中全局變量的功能,單類模式常用於註冊/查找的服務。
單類模式的UML圖如下:
單類模式有兩種實現方式:飽漢模式和餓漢模式,如下:
1.飽漢單類模式例子代碼:
- public class Singleton1{
- //飽漢模式,聲明時就創建實例對象
- public static final Singleton1 instance = new Singleton1();
- //單類模式的構造方法必須爲private,以避免通過構造方法創建對象實例,
- //並且必須顯示聲明構造方法,以防止使用默認構造方法
- private Singleton1(){}
- //單類模式必須對外提供獲取實例對象的方法
- public static Singleton1 geInstance(){
- return instance;
- }
- }
2.餓漢單類模式即延遲初始化單類方式,例子代碼:
- 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方法來防止通過序列化破壞單態模式:
- private Object readResolve(){
- return INSTANCE;
- }
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方法並沒有被同步,並且只是執行一個域的訪問,因此延遲初始化並沒有增加任何訪問成本。
4.在JDK1.5之後引入了Enum枚舉,因此在JDK1.5之後Singleton單類模式又有了第三種實現方式,也是最好的實現方式,例子如下:
- public enum Singleton4{
- INSTANCE{
- public void doSomething(){
- ……
- }
- };
- public abstract void doSomething();
- }
注意:java中除了構造方法可以創建對象實例以外,還可以通過克隆方法(clone()是Object中的protected方法)來創建對象,若單類對象直接繼承自Object對象,則如果沒有提供具體clone方法實現,則當調用克隆方法創建對象時,會拋出運行時的異常CloneNotSupportedException。
若單類類繼承了實現克隆方法的類,則在單類類中必須覆蓋父類的克隆方法,顯式拋出異常CloneNotSupportedException。
另外,實現了單類模式的類不能再有派生子類,因爲構造方式是私有的,子類無法調用父類構造方法,因此達到了Final的效果。
JDK的中單態模式的應用:
java.lang.Runtime
轉自:點擊打開鏈接