靜態(tài)工廠和構(gòu)造器有個共同的局限性:它們都不能很好地擴(kuò)展到大量的可選參數(shù)酬凳。
應(yīng)用場景示例:
? 當(dāng)一些業(yè)務(wù)場景中互纯,往往在構(gòu)建一個類的對象時尚蝌,要求構(gòu)建該對象屬性時是可選的迎变。如一個類表示包裝食品外面顯示的營養(yǎng)成分標(biāo)簽。這些標(biāo)簽
中有2個必選的:含量飘言,卡路里衣形。還有超過20個可選的:總脂肪量、飽和脂肪量热凹、膽固醇泵喘、蛋白質(zhì)等泪电。不同的產(chǎn)品的營養(yǎng)成分中均有必選成分般妙,但可選的不同產(chǎn)品所需展示的不同。在這樣的情況下相速,客戶端如果根據(jù)不同的產(chǎn)品來構(gòu)建營養(yǎng)成分標(biāo)簽?zāi)兀?/p>
1.重疊構(gòu)造器方式:第一個構(gòu)造器提供一個必要參數(shù)的構(gòu)造器碟渺,第二個構(gòu)造器提供一個可選參數(shù),第三個有兩個可選參數(shù)突诬,依次類推苫拍,最后一個構(gòu)造器包含所有可選參數(shù)。
如下示例:
?
客戶端代碼可以選擇性地調(diào)用構(gòu)造器來滿足不同場景旺隙。但也存在問題:
a. 這個構(gòu)造器調(diào)用通常需要許多不想設(shè)置的參數(shù)绒极,但還是不得不為它們傳遞值。
b. 當(dāng)有許多參數(shù)的時候蔬捷,客戶端創(chuàng)建示例的代碼會很難編寫垄提,并且難以閱讀。
2.JavaBeans方式:調(diào)用一個無參構(gòu)造器來創(chuàng)建對象周拐,然后調(diào)用setter方法來設(shè)置每個必要的參數(shù)铡俐,以及所需的可選參數(shù)。
如下示例:
這種模式相比于重疊構(gòu)造器來說妥粟,創(chuàng)建示例很容易审丘,產(chǎn)生的代碼也容易讀。
遺憾的是勾给,JavaBeans方式自身有著很嚴(yán)重的缺點(diǎn):由于整個對象的構(gòu)建被分到了幾個調(diào)用中滩报,在構(gòu)造過程中JavaBean可能處在不一致的狀態(tài)锅知。類無法僅僅通過檢驗(yàn)構(gòu)造器參數(shù)的有效性來保證一致性。如果想要保證一致性露泊,需要程序員付出更多的努力來實(shí)現(xiàn)喉镰。
3.?????? 構(gòu)建器:不直接生成想要的對象,而是讓客戶端利用所有必要的參數(shù)調(diào)用構(gòu)造器惭笑,得到一個builder對象侣姆。然后客戶端在builder對象上調(diào)用類似與setter的方法,來設(shè)置每個相關(guān)的可選參數(shù)沉噩。最后捺宗,客戶端調(diào)用無參的build方法來生成不可變的對象。
如下示例:
?
先調(diào)用類的builder必要參數(shù)的構(gòu)造創(chuàng)建一個builder川蒙,再用setter設(shè)置各個可選參數(shù)(注意使用return this;可以構(gòu)造參數(shù)鏈)蚜厉,最后調(diào)用builder方法返回一個構(gòu)建好的對象
構(gòu)建器的好處:
a)?????? Builder像個構(gòu)造器,可以在builder方法中對象域里對其參數(shù)強(qiáng)加約束條件畜眨。也可以在builder的setter方法中加約束條件昼牛,當(dāng)校驗(yàn)失敗則拋出異常,取消了對象的整個構(gòu)建康聂。
?
b)?????? Builder可以有多個可變參數(shù)
?
c)?????? Builder方法可以自動填充域贰健,也可以返回不同的對象
?
d)?????? 使用泛型的builder,JDK1.5及以后的版本提供了Builder接口恬汁。
?
?
e)?????? Java傳統(tǒng)的抽象工廠實(shí)現(xiàn)是Class對象伶椿,用newInstance()來build。
?
評價:newInstance()會主動調(diào)用無參數(shù)的構(gòu)造函數(shù)氓侧,而且沒有編譯時錯誤脊另,只能在runtime拋出異常。這破壞了編譯時的異常檢查约巷。
?
f)??????? Builder模式的不足之處:必須先構(gòu)建Builder對象偎痛。所以相比前面兩種方式它更消耗性能,必須在有很多參數(shù)時才適合使用独郎。
?
總結(jié):當(dāng)一個類中有多個參數(shù)踩麦,在創(chuàng)建該類對象的業(yè)務(wù)需求中,要求客戶端在構(gòu)建該對象時可以選定要構(gòu)建的參數(shù)時囚聚,考慮使用構(gòu)建器模式