高效Java第二條遇到多個構(gòu)造函數(shù)參數(shù)時要考慮用構(gòu)建器

靜態(tài)工廠和構(gòu)造函數(shù)共同的局限性:不能很好地適應(yīng)大量的可選參數(shù)徐裸。

重疊構(gòu)造函數(shù)模式

第一個只有必要參數(shù)的構(gòu)造函數(shù)遣鼓,
第二個構(gòu)造函數(shù)有一個可選參數(shù),
第三個構(gòu)造函數(shù)有兩個可選參數(shù)重贺。
最后一個構(gòu)造函數(shù)包含所有可選參數(shù)

r

重疊構(gòu)造函數(shù)的缺點

這個構(gòu)造函數(shù)有許多不想設(shè)置的參數(shù)骑祟,但是還是不得不為它們傳值。

隨著參數(shù)數(shù)目的增加气笙,很快就會失控次企。

重疊構(gòu)造函數(shù)模式可行,但是當(dāng)有許多參數(shù)的時候潜圃,客戶端代碼就很難編寫缸棵,并且仍然較難以閱讀。

如果讀者想要知道哪些值是什么意思谭期,必須很仔細地數(shù)著這些參數(shù)來探個究竟堵第。
一長串類型相同的參數(shù)會導(dǎo)致一些微妙的錯誤吧凉。如果客戶端不小心顛倒了其中兩個參數(shù)的順序,編譯器也不會報錯踏志,但是在程序運行的時候會出現(xiàn)錯誤的行為阀捅。

JavaBeans模式

調(diào)用一個無參數(shù)的構(gòu)造函數(shù)來創(chuàng)建對象,然后調(diào)用set方法來設(shè)置每個必要的參數(shù)狰贯,以及每個相關(guān)的可選參數(shù)也搓。


這種模式彌補了重疊構(gòu)造函數(shù)模式的不足:代碼容易閱讀。

JavaBeans模式的不足

構(gòu)造過程被分到了幾個調(diào)用中涵紊,在構(gòu)造過程中JavaBean可能處于不一致的狀態(tài)。類無法僅僅通過檢驗構(gòu)造函數(shù)參數(shù)的有效性來保證一致性幔摸。試圖使用處于不一致狀態(tài)的對象摸柄,將會導(dǎo)致失敗,這種失敗與包含錯誤的代碼是不同的既忆,調(diào)試起來非常困難驱负。

JavaBeans模式阻止了把類做成不可變類的可能,這需要程序員付出額外的努力來保證它的線程安全患雇。

JavaBeans模式不足的解決辦法

思路:對象構(gòu)造完成跃脊,不允許在解凍之前使用
通過手工“凍結(jié)”對象,可以彌補這些不足苛吱,但是這種方式十分笨拙酪术,在實踐中很少使用。此外翠储,它甚至?xí)谶\行時導(dǎo)致錯誤绘雁,因為編譯器無法確保程序員會在使用之前先在對象上調(diào)用freeze方法。

Builder模式

保證像重疊構(gòu)造函數(shù)模式那樣的安全性援所,也能保證像JavaBeans模式那么好的可讀性庐舟。

不直接生成想要的對象,而是讓客戶端利用所有必要的參數(shù)調(diào)用構(gòu)造函數(shù)(或靜態(tài)工廠)住拭,得到一個builder對象挪略。

然后客戶端在builder對象上調(diào)用類似于set的方法,來設(shè)置每個相關(guān)的可選參數(shù)滔岳。
最后客戶端調(diào)用無參的build方法來生成不可變的對象杠娱。

builder是它構(gòu)建的類的靜態(tài)成員類。

注意NutritionFacts是不可變的澈蟆,所有的默認參數(shù)值都單獨放在一個地方墨辛。builder的setter方法返回builder本身,以便可以鏈?zhǔn)秸{(diào)用趴俘。


這樣的客戶端代碼很容易編寫和閱讀睹簇。builder模式模擬了具名的可選參數(shù)奏赘。

builder像個構(gòu)造函數(shù)一樣,可以對其參數(shù)強加約束條件太惠。build方法可以檢驗這些約束條件磨淌,將參數(shù)從builder拷貝到對象中之后,并在對象域而不是builder域中對它們進行校驗凿渊,這一點很重要梁只。
如果違反了任何約束條件,build方法就應(yīng)該拋出IllegalStateException異常埃脏。

異常的詳細信息應(yīng)該顯示出違反了那個約束條件搪锣。

Builder模式對多個參數(shù)強加約束條件的方法

用多個set方法對某個約束條件必須持有的所有參數(shù)進行檢查。如果該約束條件沒有得到滿足彩掐,set方法就會拋出IllegalArgumentException构舟。
這樣有個好處,就是一旦傳遞了無效的參數(shù)堵幽,立即就會發(fā)現(xiàn)約束條件無效狗超,而不是等著調(diào)用build方法。

builder模式與構(gòu)造函數(shù)的對比

builder模式可以有多個可變的參數(shù)(多個set方法)朴下。構(gòu)造函數(shù)只能有一個可變參數(shù)努咐。

builder模式靈活性

可以利用單個builder構(gòu)建多個對象。
builder的參數(shù)可以在創(chuàng)建對象期間進行調(diào)整殴胧,也可以隨著不同的對象而改變渗稍。builder可以自動填充某些域,例如每次創(chuàng)建對象時自動增加序列號溃肪。

builder是一個抽象工廠

設(shè)置了參數(shù)的builder是一個很好的抽象工廠免胃。
客戶端可以將這樣的一個builder傳給方法,使該方法能夠為客戶端創(chuàng)建一個或多個對象惫撰。要這樣使用羔沙,必須有一個類型來表示builder。

NutritionFacts.Builder類可以實現(xiàn)Builder<NutritionFacts>接口厨钻。

帶有Builder實例的方法利用有限制的通配符類型來約束構(gòu)建器的類型參數(shù)扼雏。

Java傳統(tǒng)的抽象工廠

Java傳統(tǒng)的抽象工廠是Class對象,用newInstance方法充當(dāng)build方法的一部分夯膀。
這種用法隱含著許多問題:
newInstance方法總是企圖調(diào)用類的無參構(gòu)造函數(shù)诗充,這個構(gòu)造函數(shù)甚至可能根本不存在。如果類沒有可以訪問的無參構(gòu)造函數(shù)诱建,也不會收到編譯時錯誤蝴蜓。相反,客戶端代碼必須在運行時處理InstantiationException或IllegalAccessException,這樣既不雅觀也不方便茎匠。

newInstance方法還會傳播由無參構(gòu)造函數(shù)拋出的任何異常格仲。

Class.newInstance破壞了編譯時的異常檢查。Builder接口彌補了這些不足诵冒。

Builder模式的不足

為了創(chuàng)建對象凯肋,必須先創(chuàng)建構(gòu)建器。

builder模式比重疊構(gòu)造函數(shù)模式更加冗長汽馋,因此它只在有很多參數(shù)的時候才使用(四個以上)侮东。
但是如果預(yù)測到類將會添加更多的參數(shù),可以一開始就使用構(gòu)建器豹芯,這樣就不會有過時的構(gòu)造函數(shù)或靜態(tài)工廠悄雅。

總結(jié)

如果類的構(gòu)造函數(shù)或靜態(tài)工廠中具有多個參數(shù),設(shè)計這種類時告组,Builder模式是不錯的選擇煤伟。
與傳統(tǒng)的重疊構(gòu)造函數(shù)模式相比,使用Builder模式代碼更易于閱讀和編寫木缝,構(gòu)建器比JavaBeans更加安全。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末围辙,一起剝皮案震驚了整個濱河市我碟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌姚建,老刑警劉巖矫俺,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異掸冤,居然都是意外死亡厘托,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門稿湿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铅匹,“玉大人,你說我怎么就攤上這事饺藤“撸” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵涕俗,是天一觀的道長罗丰。 經(jīng)常有香客問我,道長再姑,這世上最難降的妖魔是什么萌抵? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上绍填,老公的妹妹穿的比我還像新娘霎桅。我一直安慰自己,他們只是感情好沐兰,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布哆档。 她就那樣靜靜地躺著,像睡著了一般住闯。 火紅的嫁衣襯著肌膚如雪瓜浸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天比原,我揣著相機與錄音插佛,去河邊找鬼。 笑死量窘,一個胖子當(dāng)著我的面吹牛雇寇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蚌铜,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼锨侯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了冬殃?” 一聲冷哼從身側(cè)響起囚痴,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎审葬,沒想到半個月后深滚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡涣觉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年痴荐,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片官册。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡生兆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出攀隔,到底是詐尸還是另有隱情皂贩,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布昆汹,位于F島的核電站明刷,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏满粗。R本人自食惡果不足惜辈末,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧挤聘,春花似錦轰枝、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至从隆,卻和暖如春诚撵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背键闺。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工命辖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留余素,地道東北人建邓。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓迈窟,卻偏偏與公主長得像,于是被迫代替她去往敵國和親挎塌。 傳聞我的和親對象是個殘疾皇子徘六,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容