1. 程式人生 > >Effective Java 第三版讀書筆記——條款1.考慮使用靜態工廠方法替代構造器

Effective Java 第三版讀書筆記——條款1.考慮使用靜態工廠方法替代構造器

lean jdb 底層 public lasso 基本 win inter nds

獲取一個類的實例的傳統方法是使用公開的構造器,除此之外,一個類還可以提供公開的靜態工廠方法(static factory method)來返回它的實例。例如 Boolean 類中的 valueOf 方法,這個方法將基本類型 boolean 轉換為一個 Boolean 對象的引用:

public static Boolean valueOf(boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE;
}

:靜態工廠方法與設計模式中的工廠方法不同。

靜態工廠方法的優點:

  • 與構造器不同,靜態工廠方法擁有自己的名字。考慮一個場景: BigInterger

    類的一個構造器 BigInterger(int, int, Random) 可能返回一個素數,然而傳統的構造器不能很直觀地表達出來,我們可以用一個靜態工廠方法 BigInteger.probablePrime 使表達變得更清晰。

    此外,如果一個類需要幾個參數類型相同的構造器,它只能打亂參數的順序來進行區別,這使得類的構造變得十分困難。此時可以考慮使用靜態工廠方法,這些方法擁有相同的參數類型,但你可以賦予它們精心挑選的名字,使它們的區別變得明顯。

  • 當靜態工廠方法被調用時,它們不需要每一次都創建一個新的對象。如開篇的 Boolean.valueOf(boolean) 所示,這個方法從來不創建對象,它只是返回 Boolean

    類中已經創建的對象:

    public static final Boolean TRUE = new Boolean(true);
    public static final Boolean FALSE = new Boolean(false);

    這有效地提升了程序的性能。這一技巧與設計模式中的享元模式(Flyweight)十分相似。

  • 靜態工廠方法可以返回其返回類型的任何子類的對象。一個可能的應用場景:API 可以返回對象,而不需要將它們的類公之於眾,以這種方式隱藏實現類將使這個 API 變得十分緊湊。這個技術適合於基於接口的框架(interface-based frameworks)。

  • 隨著輸入參數的不同,同一個靜態工廠方法可以返回不同的子類。例如 EnumSet

    類:

    public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
        Enum<?>[] universe = getUniverse(elementType);
        if (universe == null)
            throw new ClassCastException(elementType + " not an enum");
    
        if (universe.length <= 64)
            return new RegularEnumSet<>(elementType, universe);
        else
            return new JumboEnumSet<>(elementType, universe);
    }

    當底層枚舉類型的元素不超過64個時,返回 RegularEnumSet,超過64個則返回 JumboEnumSet

  • 在編寫包含靜態方法的類時,返回對象的類不需要存在。這種靈活的靜態工廠方法構成了服務提供者框架(service provider frameworks)的基礎,比如Java的數據庫連接 API(JDBC)。

靜態工廠方法的缺點

  • 只提供靜態工廠方法、不提供 publicprotected 構造器的類不能被繼承(子類化)。這也可能因禍得福:它鼓勵程序員使用組合而不是繼承。
  • 靜態工廠方法很難被程序員找到。在API文檔中,靜態工廠方法不能像構造器那樣突出,這使得程序員難以找到它們來實例化一個類。

一些靜態工廠方法的常用名稱

  • from:一個類型轉換方法,接受一個參數並返回這個類型的相應實例。

    Date d = Date.from(instant);
  • of:一個聚合方法,接受多個參數、將它們合並在一起並返回這個類型的相應實例。

    Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
  • valueOffromto 的更為詳細的替代方式。

    BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
  • instancegetInstance:返回一個實例,該實例由其參數(如果有的話)描述,但不能說具有相同的值。

    StackWalker luke = StackWalker.getInstance(options);
  • createnewInstance:與 instancegetInstance 類似,除了該方法保證每個調用返回一個新的實例。

    Object newArray = Array.newInstance(classObject, arrayLen);
  • getType:與 getInstance 類似,當工廠方法在不同的類中時使用。Type 是工廠方法返回對象的類型。

    FileStore fs = Files.getFileStore(path);
  • newType:與 newInstance 類似,當工廠方法在不同的類中時使用。Type 是工廠方法返回對象的類型。

    BufferedReader br = Files.newBufferedReader(path);
  • typegetTypenewType 的簡潔版。

    List<Complaint> litany = Collections.list(legacyLitany);

Effective Java 第三版讀書筆記——條款1.考慮使用靜態工廠方法替代構造器