前言
為什麼我們要考慮用靜态工廠方法替換構造器? 它有什麼好處,又有什麼不足?本文我們就進行一個簡單的介紹,帶你領略靜态工廠方法的美。
優點
靜态工廠方法有名稱
因為靜态工廠方法有名稱,我們可以非常友善的做到見名知義,否則使用者隻能通過閱讀參考文檔或者代碼才能知道不同的構造器具體有什麼不用
不必每次調用都建立一個新對象
Integer tt = new Integer(1);
Integer te = Integer.valueOf(1);
複制代碼
我們先看一下上面的兩個代碼,有什麼差別,看起來都是傳回了一個
Integer
,沒什麼差別,但是内裡實際上差別很大
public Integer(int value) {
this.value = value;
}
複制代碼
當我們調用構造器的時候每次都是重新建立對象
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
複制代碼
而當我們使用
valueOf
的時候,Java會為在落入
IntegerCache
中的數字傳回相同的對象,這樣就避免了建立不必要的重複對象,可以極大地提升性能!但是需要注意的是,這樣有可能造成部分基礎不熟練的同僚使用==對
Integer
進行判斷,當傳回結果落入
IntegerCache
的時候不會有不相等的問題,因為都是同一個對象,但是如果真實環境超過了[-128, 127](127可以通過參數設定),那麼這時候可能就會不一樣了,會有潛在的bug隐患。
可以傳回原傳回類型的任何子類型的對象
你可以傳回你想傳回的任何子類。一種應用是使得API可以傳回對象,同時也不會是對象的類變成公有地。用這種方式隐藏實作類會使接口變得非常簡潔。
Java 8之前,接口中不能有靜态方法,這時候我們都是依靠不可實作類來實作的
Java8之後,我們的接口中可以有靜态方法了,是以此時為接口提供不可實作類已經隻是因為接口中的靜态方法必須是
public
的。Java 9中靜态方法可以是
private
的了,但是字段仍然需要是
public
的。
傳回類可随參數而變
每次調用的時候如果我們願意,是可以通過靜态工廠方法的參數值決定傳回父類的哪種子類的,構造器就做不到這一點。
java.util.EnumSet
這個就展現了這一點,
EnumSet
被聲明為
abstract class
類型,
EnumSet
有兩種實作方式,
RegularEnumSet
和
JumboEnumSet
,但是這兩種實作方式是包私有的,不能在包外通路,是以必須使用工廠方法來建立并傳回
EnumSet
執行個體,不能通過構造函數來建立。
//noneOf方法
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
,使用者無需關心傳回的是哪種子類,隻要能用就行,甚至我們以後新加子類也對使用者沒有影響!這也是為什麼我們使用靜态工廠來進行建立的原因。 noahsnail.com/2016/09/27/…
傳回對象所屬的類,在編寫包含該靜态工廠方法的類時可不存在
這是服務提供者架構的基礎,比如JDBC的API就是如此,多個服務提供者實作一個服務,系統為服務提供者的用戶端提供多個實作,并把他們從多個實作中解耦出來。
缺點
類可能無法子類化
類如果沒有public或者protect修飾的構造器,就不能被子類化,不過這樣也好,我們最好使用複合而不是繼承。
靜态工廠方法太不起眼
一眼看過去,靜态工廠方法和靜态方法沒有什麼差別的,比如,如果我們想要查明如何實作一個EnumSet,在不搜尋的情況下可能會發現直接new不行。對我們查明如何執行個體化類會有些困難。
作者:臨時營地
連結:https://juejin.cn/post/6994696367155183653
來源:掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。