設計模式1——Singleton設計模式

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

單例模式的UML圖以下: 設計模式


單例模式有兩種實現方式:飽漢模式和餓漢模式,以下: 安全

1.飽漢單例模式例子代碼: 多線程

public class Singleton1{

    //飽漢模式,聲明時就建立實例對象
    public static final Singleton1 instance = new Singleton1();

    //單類模式的構造方法必須爲private,以免經過構造方法建立對象實例,
    //而且必須顯示聲明構造方法,以防止使用默認構造方法
    private Singleton1(){}

    //單類模式必須對外提供獲取實例對象的方法
    public static Singleton1 geInstance(){
        return instance;
    }
}

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

public class Singleton2{

    //餓漢模式,聲明時不建立實例對象
    public static Singleton2 instance;

    //單類模式的構造方法必須爲private,以免經過構造方法建立對象實例,
    //而且必須顯示聲明構造方法,以防止使用默認構造方法
    private Singleton2(){}

    //單類模式必須對外提供獲取實例對象的方法,延遲初始化的單類模式必須使用synchronized同步關鍵字,不然多線程狀況下很容易產生多個實例對象
    public static synchronized Singleton2 geInstance(){
        //延遲初始化,只有當第一次使用時才建立對象實例
        if(instance == null){
            instance = new Singleton2();
        }
        return instance;
    }
}

通常認爲飽漢模式要比餓漢模式更加安全。 線程

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

(1).雖然構造方式的訪問修飾符爲private,即除了自身之外其餘任何類都沒法調用,可是經過反射機制的setAccessiable(true)方法能夠訪問私有方法和屬性。所以Singleton單例模式必須考慮這種例外狀況。 code

(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方法第一次被調用的時候,它第一次讀取SingletonHolder.instance,致使SingletonHolder類獲得初始化;而這個類在裝載並被初始化的時候,會初始化它的靜態域,從而建立Singleton的實例,因爲是靜態的域,所以只會被虛擬機在裝載類的時候初始化一次,並由虛擬機來保證它的線程安全性。
這個模式的優點在於,getInstance方法並無被同步,而且只是執行一個域的訪問,所以延遲初始化並無增長任何訪問成本。

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

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

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

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

另外,實現了單例模式的類不能再有派生子類,由於構造方式是私有的,子類沒法調用父類構造方法,所以達到了Final的效果。

JDK的中單例模式的應用:

java.lang.Runtime

相關文章
相關標籤/搜索