前言
今天介紹建造者模式锄蹂,建造者模式又稱為生成器模式畴蹭,它是一種較為復(fù)雜坦仍、使用頻率也相對(duì)較低的創(chuàng)建型模式。建造者模式為客戶端返回的不是一個(gè)簡(jiǎn)單的產(chǎn)品撮胧,而是一個(gè)由多個(gè)部件組成的復(fù)雜產(chǎn)品桨踪。舉個(gè)簡(jiǎn)單的例子,比如我們?nèi)ベI(mǎi)電腦芹啥,買(mǎi)的是成品而不是散裝的零件锻离。
正文
建造者模式概念
建造者模式(Builder Pattern):將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離铺峭,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示。建造者模式是一種對(duì)象創(chuàng)建型模式汽纠。
產(chǎn)品的內(nèi)部表象
一個(gè)產(chǎn)品常有不同的組成成分作為產(chǎn)品的零件卫键,這些零件有可能是對(duì)象,也有可能不是對(duì)象虱朵,它們通常又叫做產(chǎn)品的內(nèi)部表象(internal representation)莉炉。不同的產(chǎn)品可以有不同的內(nèi)部表象,也就是不同的零件碴犬。使用建造模式可以使客戶端不需要知道所生成的產(chǎn)品有哪些零件絮宁,每個(gè)產(chǎn)品的對(duì)應(yīng)零件彼此有何不同,是怎么建造出來(lái)的服协,以及怎么組成產(chǎn)品绍昂。
對(duì)象性質(zhì)的建造
有些情況下,一個(gè)對(duì)象會(huì)有一些重要的性質(zhì)偿荷,在它們沒(méi)有恰當(dāng)?shù)闹抵熬接危瑢?duì)象不能作為一個(gè)完整的產(chǎn)品使用。比如跳纳,一個(gè)電子郵件有發(fā)件人地址忍饰、收件人地址、主題寺庄、內(nèi)容艾蓝、附錄等部分,而在最起碼的收件人地址得到賦值之前铣揉,這個(gè)電子郵件不能發(fā)送饶深。
有些情況下,一個(gè)對(duì)象的一些性質(zhì)必須按照某個(gè)順序賦值才有意義逛拱。在某個(gè)性質(zhì)沒(méi)有賦值之前敌厘,另一個(gè)性質(zhì)則無(wú)法賦值。這些情況使得性質(zhì)本身的建造涉及到復(fù)雜的商業(yè)邏輯朽合。這時(shí)候俱两,此對(duì)象相當(dāng)于一個(gè)有待建造的產(chǎn)品,而對(duì)象的這些性質(zhì)相當(dāng)于產(chǎn)品的零件曹步,建造產(chǎn)品的過(guò)程是建造零件的過(guò)程宪彩。由于建造零件的過(guò)程很復(fù)雜,因此讲婚,這些零件的建造過(guò)程往往被“外部化”到另一個(gè)稱做建造者的對(duì)象里尿孔,建造者對(duì)象返還給客戶端的是一個(gè)全部零件都建造完畢的產(chǎn)品對(duì)象。
建造模式利用一個(gè)導(dǎo)演者對(duì)象和具體建造者對(duì)象一個(gè)個(gè)地建造出所有的零件,從而建造出完整的產(chǎn)品對(duì)象活合。建造者模式將產(chǎn)品的結(jié)構(gòu)和產(chǎn)品的零件的建造過(guò)程對(duì)客戶端隱藏起來(lái)雏婶,把對(duì)建造過(guò)程進(jìn)行指揮的責(zé)任和具體建造者零件的責(zé)任分割開(kāi)來(lái),達(dá)到責(zé)任劃分和封裝的目的白指。
建造者模式結(jié)構(gòu)圖
在建造者模式結(jié)構(gòu)圖中包含如下幾個(gè)角色:
● Builder(抽象建造者):它為創(chuàng)建一個(gè)產(chǎn)品Product對(duì)象的各個(gè)部件指定抽象接口留晚,在該接口中一般聲明兩類方法,一類方法是buildPartX()告嘲,它們用于創(chuàng)建復(fù)雜對(duì)象的各個(gè)部件错维;另一類方法是getResult(),它們用于返回復(fù)雜對(duì)象橄唬。Builder既可以是抽象類赋焕,也可以是接口。
●ConcreteBuilder(具體建造者):它實(shí)現(xiàn)了Builder接口轧坎,實(shí)現(xiàn)各個(gè)部件的具體構(gòu)造和裝配方法宏邮,定義并明確它所創(chuàng)建的復(fù)雜對(duì)象泽示,也可以提供一個(gè)方法返回創(chuàng)建好的復(fù)雜產(chǎn)品對(duì)象缸血。
●Product(產(chǎn)品角色):它是被構(gòu)建的復(fù)雜對(duì)象,包含多個(gè)組成部件械筛,具體建造者創(chuàng)建該產(chǎn)品的內(nèi)部表示并定義它的裝配過(guò)程捎泻。
● Director(指揮者):指揮者又稱為導(dǎo)演類,它負(fù)責(zé)安排復(fù)雜對(duì)象的建造次序埋哟,指揮者與抽象建造者之間存在關(guān)聯(lián)關(guān)系笆豁,可以在其construct()建造方法中調(diào)用建造者對(duì)象的部件構(gòu)造與裝配方法,完成復(fù)雜對(duì)象的建造赤赊〈秤客戶端一般只需要與指揮者進(jìn)行交互,在客戶端確定具體建造者的類型抛计,并實(shí)例化具體建造者對(duì)象(也可以通過(guò)配置文件和反射機(jī)制)哄孤,然后通過(guò)指揮者類的構(gòu)造函數(shù)或者Setter方法將該對(duì)象傳入指揮者類中。
導(dǎo)演者角色是與客戶端打交道的角色吹截。導(dǎo)演者將客戶端創(chuàng)建產(chǎn)品的請(qǐng)求劃分為對(duì)各個(gè)零件的建造請(qǐng)求瘦陈,再將這些請(qǐng)求委派給具體建造者角色。具體建造者角色是做具體建造工作的波俄,但是卻不為客戶端所知晨逝。
一般來(lái)說(shuō),每有一個(gè)產(chǎn)品類懦铺,就有一個(gè)相應(yīng)的具體建造者類捉貌。這些產(chǎn)品應(yīng)當(dāng)有一樣數(shù)目的零件,而每有一個(gè)零件就相應(yīng)地在所有的建造者角色里有一個(gè)建造方法。這里就舉買(mǎi)電腦的例子來(lái)介紹趁窃,我們假設(shè)電腦需要2個(gè)組件苍匆,主機(jī)和顯示器。
代碼示例
下面是Computer電腦產(chǎn)品的源代碼:
public class Computer {
private String host;//主機(jī)
private String display;// 顯示屏
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public String getDisplay() {
return display;
}
public void setDisplay(String display) {
this.display = display;
}
}
下面是抽象建造者類Builder的源代碼:
public interface Builder {
public void buildHost();
public void buildDisplay();
public Computer retrieveResult();
}
下面是具體建造者類LenovoBuilder的源代碼:
public class LenovoBuilder implements Builder {
Computer computer = new Computer();
/**
* 產(chǎn)品零件建造方法1
*/
@Override
public void buildDisplay() {
//構(gòu)建產(chǎn)品的第一個(gè)零件
computer.setDisplay("聯(lián)想顯示器");
}
/**
* 產(chǎn)品零件建造方法1
*/
@Override
public void buildHost() {
//構(gòu)建產(chǎn)品的第二個(gè)零件
computer.setHost("聯(lián)想主機(jī)");
}
/**
* 產(chǎn)品返還方法
*/
@Override
public Computer retrieveResult() {
return computer;
}
}
下面是具體建造者類HuaweiBuilder的源代碼:
public class HuaweiBuilder implements Builder{
Computer computer = new Computer();
/**
* 產(chǎn)品零件建造方法1
*/
@Override
public void buildDisplay() {
//構(gòu)建產(chǎn)品的第一個(gè)零件
computer.setDisplay("華為顯示器");
}
/**
* 產(chǎn)品零件建造方法1
*/
@Override
public void buildHost() {
//構(gòu)建產(chǎn)品的第二個(gè)零件
computer.setHost("華為主機(jī)");
}
/**
* 產(chǎn)品返還方法
*/
@Override
public Computer retrieveResult() {
return computer;
}
}
下面是指揮者類Director類的源代碼:
public class Director {
/**
* 持有當(dāng)前需要使用的建造器對(duì)象
*/
private Builder builder;
/**
* 構(gòu)造方法棚菊,傳入建造器對(duì)象
* @param builder 建造器對(duì)象
*/
public Director(Builder builder){
this.builder = builder;
}
/**
* 產(chǎn)品構(gòu)造方法浸踩,負(fù)責(zé)調(diào)用各個(gè)零件建造方法
*/
public void construct(){
builder.buildHost();
builder.buildDisplay();
}
}
下面是客戶端類Client源代碼:
public class Client {
public static void main(String[]args){
Builder builder = new LenovoBuilder();
Director director = new Director(builder);
director.construct();
Computer computer = builder.retrieveResult();
System.out.println(computer.getHost());
System.out.println(computer.getDisplay());
}
}
輸出:
聯(lián)想主機(jī)
聯(lián)想顯示器
以上代碼就是模式了建造者模式的使用場(chǎng)景,其中電腦銷售人員相當(dāng)于指揮者统求,只要客戶確定電腦的類型检碗,電腦銷售人員可以通知電腦組裝人員給客戶組裝一臺(tái)電腦。
我們來(lái)看看時(shí)序圖:
客戶端負(fù)責(zé)創(chuàng)建導(dǎo)演者和具體建造者對(duì)象码邻。然后折剃,客戶端把具體建造者對(duì)象交給導(dǎo)演者,導(dǎo)演者操作具體建造者像屋,開(kāi)始創(chuàng)建產(chǎn)品怕犁。當(dāng)產(chǎn)品完成后,建造者把產(chǎn)品返還給客戶端己莺。
把創(chuàng)建具體建造者對(duì)象的任務(wù)交給客戶端而不是導(dǎo)演者對(duì)象奏甫,是為了將導(dǎo)演者對(duì)象與具體建造者對(duì)象的耦合變成動(dòng)態(tài)的,從而使導(dǎo)演者對(duì)象可以操縱數(shù)個(gè)具體建造者對(duì)象中的任何一個(gè)凌受。
總結(jié)
建造者模式的核心在于如何一步步構(gòu)建一個(gè)包含多個(gè)組成部件的完整對(duì)象阵子,使用相同的構(gòu)建過(guò)程構(gòu)建不同的產(chǎn)品,在軟件開(kāi)發(fā)中胜蛉,如果我們需要?jiǎng)?chuàng)建復(fù)雜對(duì)象并希望系統(tǒng)具備很好的靈活性和可擴(kuò)展性可以考慮使用建造者模式挠进。
1.主要優(yōu)點(diǎn)
在建造者模式中,客戶端不必知道產(chǎn)品內(nèi)部組成的細(xì)節(jié)誊册,將產(chǎn)品本身與產(chǎn)品的創(chuàng)建過(guò)程解耦领突,使得相同的創(chuàng)建過(guò)程可以創(chuàng)建不同的產(chǎn)品對(duì)象。
每一個(gè)具體建造者都相對(duì)獨(dú)立案怯,而與其他的具體建造者無(wú)關(guān)君旦,因此可以很方便地替換具體建造者或增加新的具體建造者,用戶使用不同的具體建造者即可得到不同的產(chǎn)品對(duì)象殴泰。由于指揮者類針對(duì)抽象建造者編程于宙,增加新的具體建造者無(wú)須修改原有類庫(kù)的代碼,系統(tǒng)擴(kuò)展方便悍汛,符合“開(kāi)閉原則”
可以更加精細(xì)地控制產(chǎn)品的創(chuàng)建過(guò)程捞魁。將復(fù)雜產(chǎn)品的創(chuàng)建步驟分解在不同的方法中,使得創(chuàng)建過(guò)程更加清晰离咐,也更方便使用程序來(lái)控制創(chuàng)建過(guò)程谱俭。
2.主要缺點(diǎn)
建造者模式所創(chuàng)建的產(chǎn)品一般具有較多的共同點(diǎn)奉件,其組成部分相似,如果產(chǎn)品之間的差異性很大昆著,例如很多組成部分都不相同县貌,不適合使用建造者模式,因此其使用范圍受到一定的限制凑懂。
如果產(chǎn)品的內(nèi)部變化復(fù)雜煤痕,可能會(huì)導(dǎo)致需要定義很多具體建造者類來(lái)實(shí)現(xiàn)這種變化,導(dǎo)致系統(tǒng)變得很龐大接谨,增加系統(tǒng)的理解難度和運(yùn)行成本摆碉。
3.適用場(chǎng)景
需要生成的產(chǎn)品對(duì)象有復(fù)雜的內(nèi)部結(jié)構(gòu),這些產(chǎn)品對(duì)象通常包含多個(gè)成員屬性脓豪。
需要生成的產(chǎn)品對(duì)象的屬性相互依賴巷帝,需要指定其生成順序。
對(duì)象的創(chuàng)建過(guò)程獨(dú)立于創(chuàng)建該對(duì)象的類扫夜。在建造者模式中通過(guò)引入了指揮者類楞泼,將創(chuàng)建過(guò)程封裝在指揮者類中,而不在建造者類和客戶類中笤闯。
隔離復(fù)雜對(duì)象的創(chuàng)建和使用堕阔,并使得相同的創(chuàng)建過(guò)程可以創(chuàng)建不同的產(chǎn)品。
一直覺(jué)得自己寫(xiě)的不是技術(shù)望侈,而是情懷印蔬,一篇篇文章是自己這一路走來(lái)的痕跡⊥蜒茫靠專業(yè)技能的成功是最具可復(fù)制性的,希望我的這條路能讓你少走彎路例驹,希望我能幫你抹去知識(shí)的蒙塵捐韩,希望我能幫你理清知識(shí)的脈絡(luò),希望未來(lái)技術(shù)之巔上有你也有我鹃锈。