什麼是 static factory method? 簡單來說,就是在 class 中回傳自身的 static method,像是在 Integer 或 Boolean 中 valueOf。
public static Long valueOf(String s) throws NumberFormatException { }
public static String valueOf(Object obj) { }
static factory method 相較於 constructor 的優勢1. static factory method 是方法,所以具有名稱,對開發者來說較簡單明確,例如:電信公司手機的計費方式 PricingModel 有很多種,利用方法名稱讓開發者在使用更容易。
public static PricingModel newComer();
public static PricingModel general();
public static PricingModel enterprise();
2. 對不可變物件 (immutable object) 來說,不需要每次都產生新的實體 (instance),像是 java.lang.Boolean 的 valueOf,在傳入相同的 String s 時皆會回傳同一實體。當生成新實體的成本很高時,這樣能提升效能,預先建好實體,讓相同的調用拿到同樣的實體。package java.lang;
public final class Boolean implements java.io.Serializable,
Comparable<Boolean> {
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
public static Boolean valueOf(String s) {
return parseBoolean(s) ? TRUE : FALSE;
}
}
下面的範例搭配 private constructor,讓外部無法自由的生成 PricingModel,若要使用 PricingModel 就必須調用 static factory method。public class PricingModel {
private static final PricingModel GENERAL_MODEL = ...;
public static PricingModel general() {
return GENERAL_MODEL;
}
private PricingModel() { }
}
3. static factory method 可以回傳任何繼承它的 subclass。例如:電信公司提供給員工的優待方案,定義為 StaffPricingModel 且該 class 不是 public class。class StaffPricingModel extends PricingModel {
private static final StaffPricingModel INSTANCE = ...;
static PricingModel employee() {
return StaffPricingModel.INSTANCE;
}
}
類似的用法可在 java.util.Collections 裡見到,其中 emptyList 是回傳一不可變實體,而該實體的 class 是 EmptyList,EmptyList 定義在 Collections 中,是繼承 AbstractList 的一個 static private class。public class Collections {
public static final List EMPTY_LIST = new EmptyList<>();
public static final <T> List<T> emptyList() {
return (List<T>) EMPTY_LIST;
}
private static class EmptyList<E> extends AbstractList<E>
implements RandomAccess, Serializable {
}
}
4. 可以根據開發者傳入的參數,來決定要回傳的實體。像是企業計費方案,可以依照是否是公務機來決定回傳的 PricingModel。public static PricingModel enterprise(boolean business) {
return business ? BUSI_MODEL : ENTERPRISE_MODEL;
}
5. static factory method 回傳的型別,在編寫時可以不存在,像是 Service Provider Framework,類似的應用有 JDBC API。Service Provider Interfacestatic factory method 會遇到的問題
https://stackoverflow.com/questions/2954372/difference-between-spi-and-api
1. 如果該 class 沒有提供 public 或 protected constructor,就無法被繼承。因為大部分使用 static factory method 時,會伴隨著 private constructor,如果沒有再多定義其他的 constructor 就無法被繼承,但同時也保證開發者只能調用該 class 的 static factory method 來拿到實體。
public class PricingModel {
private PricingModel() { ... }
private static final PricingModel INSTANCE = new PricingModel();
}
// error: There is no default constructor available in 'PricingModel'
public class FreePricingModel extends PricingModel { }
2. 開發者很難發現 static factory method 的存在,在 Java doc 中,沒有像 constructor 一樣,明確的標示出來。static factory method 常見的命名規則如下,在設計上應優先考慮 static factory method 而非直接提供 public constructor。- from:型態的轉換,像是 Date.from(Instant instant)。
- of 及 valueOf:像是 Boolean.valueOf(String s)。
- getInstance 及 newInstance:後者需保證每次回傳的都是新實體。
沒有留言:
張貼留言