1. 程式人生 > 其它 >比較 Java 靜態工廠方法與建構函式

比較 Java 靜態工廠方法與建構函式

1 什麼是靜態工廠方法

Java 靜態工廠方法是在方法前加上 public static,讓這個方法變為公開、靜態的方法。該方法返回該類的一個例項,就好像一個工廠生產出一個產品。所以稱之為靜態工廠方法。在 Boolean.java 中有一個靜態工廠方法示例:

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

這裡返回了一個 Boolean 例項。

2 比較靜態工廠方法與建構函式

2.1 名稱

靜態工廠方法可以根據返回例項的性質,定義出具有自描述性質的方法名稱。比如 BigInteger 類定義了一個靜態工廠方法 probablePrime,用於返回一個 BigInteger 型別的素數:

public static BigInteger probablePrime(int bitLength, Random rnd) {
        if (bitLength < 2)
            throw new ArithmeticException("bitLength < 2");

        return (bitLength < SMALL_PRIME_THRESHOLD ?
                smallPrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd) :
                largePrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd));
    }

但如果是建構函式,那麼只能是類名,比如上例中的 BigInteger。這樣就無法從名稱上判斷返回的 BigInteger 例項到底有什麼性質。

2.2 快取

每次呼叫建構函式都會建立新的物件。如果需要事先建立好物件,並快取起來,以供後期複用。那麼建構函式方式就不能滿足該需求。而靜態工廠方法就可以實現。比如 Boolean.java 中的 valueOf 方法,實際上返回的是實現建立好的靜態屬性 TRUE 與 FALSE:

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

下面是事先靜態初始化好的TRUE 與 FALSE:

/**
     * The {@code Boolean} object corresponding to the primitive
     * value {@code true}.
     */
    public static final Boolean TRUE = new Boolean(true);

    /**
     * The {@code Boolean} object corresponding to the primitive
     * value {@code false}.
     */
    public static final Boolean FALSE = new Boolean(false);

2.3 子類

擁有建構函式的類,可以被子類所繼承。但只有靜態工廠方法的類卻不行。可以使用類組合方式來解決這一問題。

2.4 總結

比較 靜態工廠方法 建構函式
名稱 可根據情況自定義名稱 只能是類名
快取 可呼叫重複物件 每次呼叫都建立新的物件
子類 不能被子類繼承 可以被子類繼承

3 靜態工廠方法命名方式

關鍵詞 說明 入參個數 示例
from 型別轉換,A 型別轉換為 B 型別。 1 public static Date from(Instant instant)
of 聚合,做合併。 n public static <E extends Enum> EnumSet of(E e1, E e2, E e3)
instance 返回例項,可能是新建的,也可能是複用已建立的例項。 n public static Object instance(int length)
create 返回新建的例項。 n public static Object create(int length)
type 工廠方法不在要返回的類例項中,type 是要返回的類名稱。 n public static ArrayList list(Enumeration e)

最後一個示例,方法定義在 Collections 中,要返回的是 ArrayList 例項,所以被命名為 list。

public static <T> ArrayList<T> list(Enumeration<T> e) {
        ArrayList<T> l = new ArrayList<>();
        while (e.hasMoreElements())
            l.add(e.nextElement());
        return l;
    }

建議優先考慮使用靜態工廠方法來例項化類。


JoshuaBloch. Effective Java中文版.3版[M]. 機械工業出版社, 2018.p.4-8.