1.介紹
允許用戶在不知道內(nèi)部構(gòu)建細(xì)節(jié)的情況下,可以更精細(xì)地控制對象的構(gòu)造流程。為了將構(gòu)建復(fù)雜對象的過程和它的部件解耦,使得構(gòu)建過程和部件的表示隔離。
1.這個對象由多個小部分組成
2.可以配置該對象由其中哪幾個分類組成
3.不同的組成,可以得到不同的結(jié)果。(雖然都是同一類對象,但細(xì)節(jié)上不一樣)
2.定義
建造者模式(Builder),見一個復(fù)雜對象的構(gòu)建與它的標(biāo)識分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
3.使用場景
- 相同的方法,不同的執(zhí)行循序,產(chǎn)生不同的時間結(jié)果時。
- 多個部件或零件,都可以裝配到一個對象中,但是產(chǎn)生的運行結(jié)果又不相同。
- 產(chǎn)品類非常復(fù)雜,或者產(chǎn)品類中的調(diào)用循序不同產(chǎn)生了不同的作用,這個時候使用建造者模式非常適合。
- 當(dāng)初始化一個對象非常復(fù)雜,如參數(shù)多且很多參數(shù)都有默認(rèn)值時。
簡單理解就是:當(dāng)創(chuàng)建對象時參數(shù)過多、創(chuàng)建過程復(fù)雜、得到的結(jié)果多變時可以考慮使用 Builder 模式。

舉個例子
一個游戲扮演游戲,如王者農(nóng)藥。我們在操作時可以選擇不同的人物角色,他們有之間的劃分:
- 人物名稱:李元芳(輸出爆炸)、呂布(團(tuán)戰(zhàn)跳大收割)、程咬金(瘋狂補血)、安其拉(大頭發(fā))...我基本上玩這幾個吧
- 人物類型有:戰(zhàn)士、坦克、刺客、法師、射手。
- 武器:激光射線、雙斧、斬刀、飛刀...
- 發(fā)型:超長頭發(fā)、短發(fā)、禿頭、配大耳朵的頭發(fā)
- 戰(zhàn)斗類型:持續(xù)輸出、收割、遠(yuǎn)程攻擊、生存等
如果使用普通的方式構(gòu)建對象可能會是這樣的:
public Hero(String name,Profession profession, Weapon weapon ,HairType hairType, Armor armor) {
}
可以看出這樣做的缺點:
- 1、參數(shù)超多,容易誤導(dǎo)或傳錯或位子放錯。
- 2、當(dāng)有新的類型添加時,之前創(chuàng)建的角色都要修改。
那么怎么辦呢? 很容易想到:構(gòu)造函數(shù)中直接傳遞個 POJO 不就行了?! 確實是這樣的,但是我們還可以做些改變,使得這個 POJO 更方便使用:
- 1、這個 POJO 基本上只屬于這個類使用,所以我們一般都定義在該類中。
- 2、這個 POJO 的構(gòu)造函數(shù)不能是多個參數(shù)了,它的出現(xiàn)就是為了解決參數(shù)過多的問題,當(dāng)然就不能有多參數(shù)的構(gòu)造(可以有一兩個參數(shù)的構(gòu)造)。
- 3、這個 POJO 在配置的時候,希望是鏈?zhǔn)降?,這樣更方便了是吧,直接點點點點... 的就可以創(chuàng)建了。
- 4、既然有了這個 POJO 就不能讓原來對象被外部創(chuàng)建了是吧,那么外部的對象類的構(gòu)造函數(shù)就應(yīng)該設(shè)置為 private 防止外部創(chuàng)建。
- 5、直接叫 POJO 不太好聽吧,那么重新定義個名字唄,(⊙v⊙)嗯,它是用來創(chuàng)建復(fù)雜對象的,那就叫 Builder 吧。
Talk is cheap,show me the code
我們先來看下 Builder 類吧:
public static class Builder {
private final String name; // 名稱
private final Profession profession; // 類型
private HairType hairType; // 發(fā)型
private Armor armor; // 戰(zhàn)斗類型
private Weapon weapon; // 武器
public Builder(Profession profession, String name) {
if (profession == null || name == null) {
throw new IllegalArgumentException("profession and name can not be null");
}
this.profession = profession;
this.name = name;
}
public Builder withHairType(HairType hairType) {
this.hairType = hairType;
return this;
}
public Builder withArmor(Armor armor) {
this.armor = armor;
return this;
}
public Builder withWeapon(Weapon weapon) {
this.weapon = weapon;
return this;
}
public Hero build() {
return new Hero(this);
}
}
那么我們回頭看下 Hero 類發(fā)生了什么變化吧:
public final class Hero {
private final Profession profession;
private final String name;
private final HairType hairType;
private final Armor armor;
private final Weapon weapon;
private Hero(Builder builder) {
this.profession = builder.profession;
this.name = builder.name;
this.hairColor = builder.hairColor;
this.weapon = builder.weapon;
this.armor = builder.armor;
}
}
不得不承認(rèn),代碼是多了不少,但是為了以后應(yīng)對更好理解、需求變化,還是認(rèn)了吧。程序里面唯一不變的就是變化
我們再看下爽點的地方,對象的創(chuàng)建過程:
Hero mage = new Hero.Builder(Profession.MAGE, "安其拉")
.withHairColor(HairColor.RED)
.withWeapon(Weapon.LASER)
.build();
參考:
- java-design-patterns
- Android源碼設(shè)計模式解析與實戰(zhàn)