總體說來通惫,建造者模式適合于一個(gè)具有較多的零件(屬性)的產(chǎn)品(對(duì)象)的創(chuàng)建過程鼻忠。根據(jù)產(chǎn)品創(chuàng)建過程中零件的構(gòu)造是否具有一致的先后順序,可以將其分為如下兩種形式凳兵。
一百新、通過Client、Director庐扫、Builder和Product形成的建造者模式
Builder負(fù)責(zé)Product類對(duì)象的具體過程構(gòu)建饭望,Director負(fù)責(zé)指導(dǎo)Build,要求Builder按照其指定的順序去完成Produt的構(gòu)造形庭。最后通過Builder返回建造后的結(jié)果铅辞。
簡單地說,就好象我要一座房子住萨醒,可是我不知道怎么蓋(簡單的砌墻斟珊,層次較低),也不知道怎么樣設(shè)計(jì)(建幾個(gè)房間验靡,幾個(gè)門好看倍宾,層次較高),于是我需要找一幫民工胜嗓,他們會(huì)砌墻高职,還得找個(gè)設(shè)計(jì)師,他知道怎么設(shè)計(jì)辞州,我還要確保民工聽設(shè)計(jì)師的領(lǐng)導(dǎo)怔锌,而設(shè)計(jì)師本身也不干活,光是下命令变过,這里砌一堵墻埃元,這里砌一扇門,這樣民工開始建設(shè)媚狰,最后岛杀,我可以向民工要房子了。在這個(gè)過程中崭孤,設(shè)計(jì)師是什么也沒有类嗤,除了他在腦子里的設(shè)計(jì)和命令糊肠,所以要房子也是跟民工要,記住了遗锣!
如果我們需要將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離货裹,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示的意圖時(shí),我們可以使用 Builder模式精偿,又叫生成器模式弧圆。如果我們用了Builder模式,那么用戶就只需要指定需要建造的類型就可以得到它們笔咽,而具體建造的過程和細(xì)節(jié)就不需要知道了搔预。
比如現(xiàn)在我們有一個(gè)這樣的使用場景,需要在屏幕上畫小人拓轻,人要有頭手腳斯撮,要畫不同的人,胖的小人扶叉,瘦的小人勿锅,矮的小人。按照通常的寫法枣氧,會(huì)有很多的樣板代碼溢十,畫人的頭,畫人腳手达吞,如果一不小心张弛,非常容易缺胳膊少腿。
二酪劫、通過靜態(tài)內(nèi)部類等方式實(shí)現(xiàn)的零件無序話構(gòu)造:
遇到多個(gè)構(gòu)造器參數(shù)時(shí)要考慮用構(gòu)建器吞鸭。靜態(tài)工廠和構(gòu)造器有個(gè)共同的局限性:它們都不能很好地?cái)U(kuò)展到大量的可選參數(shù)。
考慮這樣的一個(gè)場景:用一個(gè)類表示包裝食品外面顯示的營養(yǎng)成分標(biāo)簽覆糟。這些標(biāo)簽中有幾個(gè)域是必需的:每份的含量刻剥、每罐的含量以及每份的卡路里,還有超過20個(gè)可選域:總脂肪量滩字、飽和脂肪量造虏、轉(zhuǎn)化脂肪、膽固醇麦箍、鈉等等漓藕。
程序員一向習(xí)慣采用重疊構(gòu)造器模式,在這種模式下挟裂,你提供第一個(gè)只有必要參數(shù)的構(gòu)造器享钞,第二個(gè)構(gòu)造器有一個(gè)可選參數(shù),第三個(gè)有兩個(gè)可選參數(shù)诀蓉,以此類推嫩与,最后一個(gè)構(gòu)造器包含所有可選參數(shù)寝姿。重疊構(gòu)造器模式可行交排,但是當(dāng)有許多參數(shù)的時(shí)候划滋,客戶端代碼會(huì)很難編寫,并且仍然難以閱讀埃篓。一長串類型相同的參數(shù)會(huì)導(dǎo)致一些微妙的錯(cuò)誤处坪。如果客戶端不小心顛倒了其中兩個(gè)參數(shù)的順序,編譯器也不會(huì)出錯(cuò)架专,但是程序在運(yùn)行時(shí)會(huì)出現(xiàn)錯(cuò)誤的行為同窘。
public class Client {
public static void main(String[] args) {
User.Builder builder = new User.Builder();
User user = builder.setName("corn").setAge(100).setAddress("廣州").build();}}
class User {
private String name;
private int age;
private String address;
public String getName() {return name;}
public int getAge() {return age;}
public String getAddress() {return address;}
public static class Builder {
private User user = new User();
public Builder setName(String name) {
user.name = name;return this;}
public Builder setAge(int age) {user.age = age;return this;}
public Builder setAddress(String address) {
user.address = address;return this;}
public User build() {return user;}}}