靜態(tài)工廠和構(gòu)造器有個共同的局限性:它們都不能很好地擴展到大量的可選參數(shù)。
應用場景示例:
? 當一些業(yè)務場景中,往往在構(gòu)建一個類的對象時,要求構(gòu)建該對象屬性時是可選的。如一個類表示包裝食品外面顯示的營養(yǎng)成分標簽。這些標簽
中有2個必選的:含量,卡路里。還有超過20個可選的:總脂肪量、飽和脂肪量、膽固醇、蛋白質(zhì)等。不同的產(chǎn)品的營養(yǎng)成分中均有必選成分,但可選的不同產(chǎn)品所需展示的不同。在這樣的情況下,客戶端如果根據(jù)不同的產(chǎn)品來構(gòu)建營養(yǎng)成分標簽呢?
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ù),但還是不得不為它們傳遞值。
b. 當有許多參數(shù)的時候,客戶端創(chuàng)建示例的代碼會很難編寫,并且難以閱讀。
2.JavaBeans方式:調(diào)用一個無參構(gòu)造器來創(chuàng)建對象,然后調(diào)用setter方法來設置每個必要的參數(shù),以及所需的可選參數(shù)。
如下示例:

這種模式相比于重疊構(gòu)造器來說,創(chuàng)建示例很容易,產(chǎn)生的代碼也容易讀。
遺憾的是,JavaBeans方式自身有著很嚴重的缺點:由于整個對象的構(gòu)建被分到了幾個調(diào)用中,在構(gòu)造過程中JavaBean可能處在不一致的狀態(tài)。類無法僅僅通過檢驗構(gòu)造器參數(shù)的有效性來保證一致性。如果想要保證一致性,需要程序員付出更多的努力來實現(xiàn)。
3.?????? 構(gòu)建器:不直接生成想要的對象,而是讓客戶端利用所有必要的參數(shù)調(diào)用構(gòu)造器,得到一個builder對象。然后客戶端在builder對象上調(diào)用類似與setter的方法,來設置每個相關的可選參數(shù)。最后,客戶端調(diào)用無參的build方法來生成不可變的對象。
如下示例:
?

先調(diào)用類的builder必要參數(shù)的構(gòu)造創(chuàng)建一個builder,再用setter設置各個可選參數(shù)(注意使用return this;可以構(gòu)造參數(shù)鏈),最后調(diào)用builder方法返回一個構(gòu)建好的對象
構(gòu)建器的好處:
a)?????? Builder像個構(gòu)造器,可以在builder方法中對象域里對其參數(shù)強加約束條件。也可以在builder的setter方法中加約束條件,當校驗失敗則拋出異常,取消了對象的整個構(gòu)建。
?
b)?????? Builder可以有多個可變參數(shù)
?
c)?????? Builder方法可以自動填充域,也可以返回不同的對象
?
d)?????? 使用泛型的builder,JDK1.5及以后的版本提供了Builder接口。
?

?
e)?????? Java傳統(tǒng)的抽象工廠實現(xiàn)是Class對象,用newInstance()來build。
?
評價:newInstance()會主動調(diào)用無參數(shù)的構(gòu)造函數(shù),而且沒有編譯時錯誤,只能在runtime拋出異常。這破壞了編譯時的異常檢查。
?
f)??????? Builder模式的不足之處:必須先構(gòu)建Builder對象。所以相比前面兩種方式它更消耗性能,必須在有很多參數(shù)時才適合使用。
?
總結(jié):當一個類中有多個參數(shù),在創(chuàng)建該類對象的業(yè)務需求中,要求客戶端在構(gòu)建該對象時可以選定要構(gòu)建的參數(shù)時,考慮使用構(gòu)建器模式