在日常程式設計中,擷取類的執行個體通常采用構造器的方法。還有另一種方法叫作“靜态工廠方法(Static Factory Method)”。譬如Boolean類中這段代碼:
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
使用靜态工廠方法優點
-
靜态工廠方法有名稱
構造函數的方法名比較單調,隻能與類名相同。特别是當有多個構造函數時,有可能不能很好的區分彼此之間的參數差別。而靜态方法為普通的方法,名字可以依據方法的作用來設定。
譬如類java.util.concurrent.Executors,其中的靜态方法如下:
//建立一個包含固定數量線程的線程池 public static ExecutorService newFixedThreadPool(int nThreads) //建立一個線程池,使線程能支援設定等級的并發 public static ExecutorService newWorkStealingPool(int parallelism)
-
靜态工廠方法可以每次不必建立新對象
每次調用構造函數都需要建立新對象。但是在靜态工廠方法中,則可以傳回緩存的對象或者預先建構的對象。譬如最上面的
代碼。public static Boolean valueOf(boolean b)
-
靜态工廠方法的傳回類型可以為子類型對象
這種靈活性有很多好處。
- 靜态工廠方法的傳回對象的類可以不用是
public
的,這樣隐藏了類的實作細節
大家可以檢視
類的代碼,裡面提供了很多的靜态工廠方法,如:Collections
public class CollectionDemo { public static void main(String[] args) { //list1為同步清單 List<Object> list1 = Collections.synchronizedList(Lists.newArrayList()); //list2為不可改變的清單 List<Object> list2 = Collections.unmodifiableList(Lists.newArrayList()); //list1和list2雖都為清單,但也不是同種清單,list1為同步清單,list2則為不可改變的清單 } }
-
靜态工廠方法的傳回對象的類的實作是可以随着版本疊代進行修改的
在實際開發中大家都有疊代的痛苦,如果某個接口修改了實作也需要調用方進行修改,那是很痛苦的。這裡我們可以參考
EnumSet
。
檢視
的代碼發現,其沒有開放的構造方法,僅提供許多靜态工廠方法,如下:EnumSet
以EnumSet類型中的noneOf方法為例說明,當方法 描述 static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType)
建立包含
所有元素的elementType
對象EnumSet
EnumSet<E> clone()
傳回目前
對象的複制結果EnumSet
static <E extends Enum<E>> EnumSet<E> complementOf(EnumSet<E> s)
建立包含
對象,且包含elementType
中的所有元素s
static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c)
建立
對象,且用EnumSet
中的元素進行初始化c
static <E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s)
建立
對象,且用EnumSet
中的元素進行初始化s
static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType)
用指定的類型建立空的
對象EnumSet
static <E extends Enum<E>> EnumSet<E> of(E e)
建立
對象,并用EnumSet
初始化e
static <E extends Enum<E>> EnumSet<E> of(E first, E... rest)
建立
對象,并用EnumSet
、first
元素初始化rest
static <E extends Enum<E>> EnumSet<E> of(E e1, E e2)
建立
對象,并用EnumSet
、e1
元素初始化e2
static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3)
建立
對象,并用EnumSet
、e1
、e2
元素初始化e3
static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4)
建立
對象,并用EnumSet
、e1
、e2
、e3
元素初始化e4
static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4, E e5)
建立
對象,并用EnumSet
、e1
、e2
、e3
、e4
元素初始化e5
static <E extends Enum<E>> EnumSet<E> range(E from, E to)
建立
對象,并用EnumSet
至from
之間的元素初始化to
的元素個數小于64時,則調用elementType
,否則調用RegularEnumSet
。當在以後的疊代中,JumboEnumSet
的性能足以支撐超過64個元素時,我們完全可以删除調用RegularEnumSet
的實作,而不會影響調用方。JumboEnumSet
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> var0) { Enum[] var1 = getUniverse(var0); if (var1 == null) { throw new ClassCastException(var0 + " not an enum"); } else { return (EnumSet)(var1.length <= ? new RegularEnumSet(var0, var1) : new JumboEnumSet(var0, var1)); } }
- 靜态工廠方法的傳回對象的類,在編寫的時候可以不必存在,也即服務提供者架構。
- 靜态工廠方法的傳回對象的類可以不用是
- 靜态工廠方法在建立參數化類型執行個體時,使代碼更簡潔。這在高版本的
JDK
中已經不存在。
此處的意思是,之前在建立某些類時,譬如
,片段Map<String, List<String>> map = new HashMap<String, List<String>>()
需要重複寫兩次,在高版本String, List<String>
中已經可以不用這樣寫了,可以寫為JDK
Map<String, List<String>> map = new HashMap()
使用靜态工廠缺點
- 類若不包含公有的或受保護的構造器,則不能被子類化
- 與其他靜态方法相比沒有差別。意思是指使用者可能不明白此靜态工廠方法是用來執行個體化對象的,沒有構造函數那麼直白。平時程式設計中,盡量采用易懂的方法命名來表示,如
、newInstance
、getInstance
、getType
、newType
、valueOf
這樣的命名of