Effective Java筆記第一章建立和銷燬物件第三節用私有構造器或者列舉型別強化Singleton屬性

越知越無知發表於2020-12-12

Effective Java筆記第一章建立和銷燬物件

第三節用私有構造器或者列舉型別強化Singleton屬性

1.Singleton指僅僅被例項化一次的類。使類成為Singleton會使他的客戶端測試變得十分困難。Java1.5之前,實現Singleton有兩種方法,這兩種方法都要把構造器保持為私有的,並匯出公有的靜態成員變數,以便允許客戶端能訪問該類的唯一例項。

2.公有靜態成員是個final域

public class Demo1 {
    //公有靜態成員final域
    public static final Demo1 INSTANCE = new Demo1();
    //私有構造防止例項化
    private Demo1() {
    }

    public void leaveTheBuilding(){

    }

    public static void main(String[] args) {
        Demo1 demo1 = Demo1.INSTANCE;
        System.out.println(demo1);
        Demo1 demo2 = Demo1.INSTANCE;
        System.out.println(demo2);
    }

優點:
1)私有構造器僅被呼叫一次,由於缺少公有的或者受保護的構造器,所以保證了類的全域性唯一性。
2)公有域方法的主要好處在於,組成類的成員的宣告很清楚地表明瞭這個類是個Singleton,公有的靜態域是final的,所以該域將總是包含相同的物件引用。
缺點:
享有特權的客戶端可以藉助AccessibleObject.setAccessible方法,通過反射機制呼叫私有構造器。如果要抵禦這種攻擊,可以修改構造器,讓他在被要求建立第二個例項的時候丟擲異常。

3.公有的成員是個靜態工廠方法

public class Demo2 {
    //公有靜態成員final域
    private static final Demo2 INSTANCE=new Demo2();
    //私有構造防止例項化
    private Demo2(){

    }
    //靜態工廠獲取物件
    public static Demo2 getInstance(){
        return INSTANCE;
    }

    public void leaveTheBuilding(){

    }

    public static void main(String[] args) {
        Demo2 demo2 = Demo2.getInstance();
        System.out.println(demo2);
        Demo2 demo21 = Demo2.getInstance();
        System.out.println(demo21);
    }

}

工廠方法的優勢:
1)提供了靈活性,在不改變其API的前提下,我們可以改變該類是否應該為Singleton的想法。
2)優勢與泛型有關。
3)public域的方法比較簡單。
缺點:
容易被修改,比如改成為每個呼叫該方法的執行緒返回一個唯一例項。

4.包含單個元素的列舉型別

public enum  Demo3 {
    INSTANCE;
    public void leaveThebuilding(){}

    public static void main(String[] args) {
        Demo3 demo3 = Demo3.INSTANCE;
        System.out.println(demo3);
        Demo3 demo31 = Demo3.INSTANCE;
        System.out.println(demo31);
    }
}

優勢:
1)與共有域方法相近,更加簡潔,無償提供了序列化機制,絕對防止多次例項化,雖然還沒推廣,但單元素的列舉型別已經成為實現Singleton的最佳方法。

相關文章