1. 程式人生 > >Effective Java 第三版讀書筆記——條款3:使用私有構造器或列舉型別來強制實現 singleton 屬性

Effective Java 第三版讀書筆記——條款3:使用私有構造器或列舉型別來強制實現 singleton 屬性

單例(singleton)就是一個只例項化一次的類。使類成為單例可能會使它的測試變得困難,因為除非它實現了作為其型別的介面,否則不可能用模擬實現來代替這個單例。下面是幾種實現單例的方法:

使用 public field 方法

// Singleton with public final field
public class Elvis {
    public static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }
    public void leaveTheBuilding() { ... }
}

私有構造器只會被呼叫一次來初始化用 public static final

修飾的屬性 INSTANCE。因為沒有 publicprotected 的構造器,這裡只會存在一個 Elvis 例項。

該方法的優點:

  • API 明確表示這個類就是一個單例。公共靜態屬性是 final 的,所以它總是包含相同的物件引用。
  • 這個方法很簡單。

使用 static factory 方法

// Singleton with static factory
public class Elvis {
    private static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }
    public static Elvis getInstance() { return INSTANCE; }
    public void leaveTheBuilding() { ... }
}

所有對 Elvis.getInstance 的呼叫都返回相同的物件引用,並且不會建立其他的Elvis例項。

該方法的優點:

  • 可以方便地將類的實現改為非單例,並且使用者程式碼不需要改變。
  • 可以編寫一個泛型單例工廠。
  • 方法引用可以被用作 supplier,例如 Elvis::instance 等同於 Supplier<Elvis>

使用只有一個元素的列舉型別

// Enum singleton - the preferred approach
public enum Elvis {
    INSTANCE;
    public void leaveTheBuilding() { ... }
}

這個方法與 public field 方法相似,但是更加簡潔。這個方法看起來有一點不自然,但它通常是實現單例的最好方法。

注意:如果單例必須繼承 Enum 以外的父類(儘管可以宣告一個 Enum 來實現介面),那麼就不能使用這種方法。