靜態工廠方法,也不知道為何叫這個名字。其實也就是一個靜態函數,可以替代構造函數用。大名鼎鼎的 [guava](https://github.com/google/guava) 就大量使用這種模式,這是非常有用的模式。 ...
靜態工廠方法,也不知道為何叫這個名字。其實也就是一個靜態函數,可以替代構造函數用。大名鼎鼎的 guava 就大量使用這種模式,這是非常有用的模式。
比如是
Integer i = Integer.valueOf(123);
Boolean bool = Boolean.valueOf(true);
//guava 的方法
ConcurrentMap<String,Integer> concurrentMap = Maps.newConcurrentMap();
ArrayList<Integer> array = Lists.newArrayList(1,2,3,4,5);
那麼為什麼要用靜態工廠方法呢?
《effective java》解釋得挺好的,下麵我就進行“人類的本質”,並加點個人的見解。
靜態工廠方法,可以不用創建新的對象
可以去看下 Integer.valueOf
函數
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
如果是 -128 到 127,通過 valueOf
構造對象能從對象池中直接獲取,避免了對象重覆構建!
如果是 Boolean 對象,只有 True 和 False 效果就更明顯了。
有名字就是好
比如有個 User 類,有 Name,Address,Email等欄位。有些數據只需 Name、和 Email 欄位就可以了,有些欄位只需 Name 和 Address 欄位就可以了。但這確實不能創建兩個相同類型的構造器!但你可以創建newNameWithEmail
或者 newNameWithAddress
的靜態工廠函數。方便!
免去繁瑣,不用寫太多的通配符
這個也是被 guava
發揚廣大,
比如:正常構造一個 HashMap
Map<String,List<String>> map = new HashMap<String,List<String>>();
前面類型都定義好了,為毛還要寫 new HashMap<String,List<String>>();
這樣的一大串東西;
而guava
中只要這樣就可以了,而且還是類型安全的!
Map<String,List<String>> map = Maps.newHashMap();
怎樣做到的呢?看下以前版本的實現。
public static <K, V> HashMap<K, V> newHashMap() {
return new HashMap<K,V>();
}
其實 ,java 官方也發現這個問題的 java 7 在這樣一種語法糖
Map<String,List<String>> map = new HashMap<>();
java 9 後 有了 var
語法糖。可以寫成
var map = new HashMap<String,List<String>>();
靜態工廠函數的這個優勢可有可無了
可以返回原返回類型的任何子類型
比如 EnumSet 根據 universe 數組的長度可以返回不同類型的 EnumSet
public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
implements Cloneable, java.io.Serializable {
EnumSet(Class<E>elementType, Enum[] universe) {
}
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
}
}
確實是有點用,這種用法我是用得比較少。不喜歡用這樣方式。覺得還不如不封裝(逃
靜態工廠方法的缺點
個人覺得,沒啥缺點,甚至覺得每個類最好用靜態工廠函數替代構造函數!最好還是把構造函數變成 private (逃。
這樣可以強制不使用繼承,只能用組合。
以上