最近開(kāi)始讀《Effective Java》這本書,本文只是對(duì)所讀過(guò)章節(jié)的記錄以及個(gè)人理解與總結(jié),理解不當(dāng)之處,請(qǐng)見(jiàn)諒。?
? ? ? ?在Java中,創(chuàng)建新對(duì)象的方式一般是通過(guò)調(diào)用類的構(gòu)造器方法來(lái)完成,然而創(chuàng)建對(duì)象的方式也可以通過(guò)類靜態(tài)工廠的方法來(lái)完成。? 例子如下:?
public static Boolean valueOf(boolean b) {
? ? return b ? Boolean.TRUE : Boolean.FALSE;?
}? ?
通過(guò)類靜態(tài)工廠方法創(chuàng)建對(duì)象的方式有以下幾個(gè)優(yōu)勢(shì):?
1.類靜態(tài)工廠方法可以允許自定義方法名稱。
? ? ? ?構(gòu)造器的方法名是固定的,當(dāng)遇上相同的參數(shù)需要構(gòu)造兩種不同的對(duì)象時(shí),構(gòu)造器往往會(huì)陷入困境,而類靜態(tài)工廠方法可以通過(guò)不同的方法名清晰地向客戶端程序員提供目標(biāo)對(duì)象的信息。?
2.在類靜態(tài)工廠方法中,可以選擇返回一個(gè)新對(duì)象或者已經(jīng)存在的對(duì)象。
? ? ? ?構(gòu)造器方法的使命就是返回一個(gè)新對(duì)象,而類靜態(tài)工廠方法則有選擇權(quán),文章開(kāi)始的例子以及單例模式中,類靜態(tài)工廠方法都是返回一個(gè)已存在的對(duì)象,而假如在靜態(tài)工廠方法中直接調(diào)用構(gòu)造器方法則可以直接返回一個(gè)新對(duì)象。?
3.類靜態(tài)工廠方法可以返回任何其返回類型子類的對(duì)象。
? ? ? ?構(gòu)造器方法只能返回當(dāng)前類的對(duì)象,而類的靜態(tài)工廠方法的返回類型是接口或者抽象類時(shí),該方法就可以返回其返回類型的實(shí)現(xiàn)類或者子類的對(duì)象。這樣做的好處在于API的使用者無(wú)需關(guān)心具體的實(shí)現(xiàn)類。依賴接口而非實(shí)現(xiàn)是一種非常好的編程實(shí)踐。??
4.類構(gòu)造器可以避免重復(fù)編寫類型。
? ? ? ?例如,在構(gòu)造一個(gè)Map對(duì)象時(shí):
? ? ? ?Map<String, List<String>> m = new HashMap<String,List<String>>();
? ? ? ?聲明和創(chuàng)建對(duì)象時(shí)都需要填寫具體的類型,用起來(lái)非常繁瑣。??
? ? ? ?假如在HashMap中添加這樣一個(gè)類靜態(tài)工廠方法:
? ? ? ?public static <K,V>HashMap<K,V> newInstance() {
? ? ? ? ? ? ?return new HashMap<K,V>();
? ? ? ? }
? ? ? ?創(chuàng)建新對(duì)象時(shí),可以寫成:
? ? ? ?Map<String,List<String>> m = HashMap.newInstance();
? ? ? ?省略了在創(chuàng)建新對(duì)象時(shí)寫類型的必要。實(shí)際上,在Java 8中,已經(jīng)支持在創(chuàng)建新對(duì)象時(shí)不需要再次填寫類型,如下: ?
? ? ? ?Map<String,List<String>> m = new HashMap<>();
? ? ? ?所以隨著語(yǔ)言的改進(jìn),該優(yōu)勢(shì)已不再明顯。
使用類靜態(tài)工廠方法創(chuàng)建對(duì)象主要有兩點(diǎn)劣勢(shì):
1.沒(méi)有public或者protected權(quán)限構(gòu)造器的類不能被繼承。
? ? ? ?擁有類靜態(tài)工廠方法的類,為了阻止客戶端程序員通過(guò)調(diào)用構(gòu)造器創(chuàng)建新對(duì)象,通常會(huì)將所有構(gòu)造器的權(quán)限置為private,這就導(dǎo)致該類無(wú)法被繼承,并且客戶端程序員必須使用組合而非繼承,在某些情境下,這也不是一件壞事。
2.靜態(tài)工廠方法往往與其他靜態(tài)方法在JavaDoc中沒(méi)有區(qū)分度。
? ? ? ?構(gòu)造方法在JavaDoc中比靜態(tài)工廠方法能夠更加吸引客戶端程序員的注意,解決這個(gè)的辦法是為靜態(tài)工廠方法添加注釋或者使用以下一些比較通用的靜態(tài)工廠方法名稱。
valueOf -- 類型轉(zhuǎn)換
of -- 同valueOf
getInstance -- 獲取一個(gè)實(shí)例,單例模式中常用此命名
newInstance -- 創(chuàng)建一個(gè)新的實(shí)例,保證與其他的實(shí)例不同
getType -- 同getInstance,只不過(guò)是創(chuàng)建一個(gè)不同于當(dāng)前類型的對(duì)象
newType -- 同newInstance,只不過(guò)是創(chuàng)建一個(gè)不同于當(dāng)前類型的對(duì)象
最后,最重要的問(wèn)題來(lái)了,什么情境下采用哪種方式最合適?
? ? ? 其實(shí)對(duì)于這個(gè)問(wèn)題來(lái)說(shuō),沒(méi)有標(biāo)準(zhǔn)的答案,能夠充分發(fā)揮靜態(tài)工廠方法創(chuàng)建對(duì)象優(yōu)勢(shì),而且能避免構(gòu)造器劣勢(shì)的情境下,就該選擇使用靜態(tài)工廠方法;反之,同理。