設(shè)計(jì)模式干貨系列:(六)建造者模式【學(xué)習(xí)難度:★★★★☆,使用頻率:★★☆☆☆】

前言

今天介紹建造者模式锄蹂,建造者模式又稱為生成器模式畴蹭,它是一種較為復(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ù)之巔上有你也有我鹃锈。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末荤胁,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子屎债,更是在濱河造成了極大的恐慌仅政,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盆驹,死亡現(xiàn)場(chǎng)離奇詭異圆丹,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)躯喇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)辫封,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)硝枉,“玉大人,你說(shuō)我怎么就攤上這事倦微∑尬叮” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵欣福,是天一觀的道長(zhǎng)责球。 經(jīng)常有香客問(wèn)我,道長(zhǎng)拓劝,這世上最難降的妖魔是什么棕诵? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮凿将,結(jié)果婚禮上校套,老公的妹妹穿的比我還像新娘。我一直安慰自己牧抵,他們只是感情好笛匙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著犀变,像睡著了一般妹孙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上获枝,一...
    開(kāi)封第一講書(shū)人閱讀 51,155評(píng)論 1 299
  • 那天蠢正,我揣著相機(jī)與錄音,去河邊找鬼省店。 笑死嚣崭,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的懦傍。 我是一名探鬼主播雹舀,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼粗俱!你這毒婦竟也來(lái)了说榆?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤寸认,失蹤者是張志新(化名)和其女友劉穎签财,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體偏塞,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡唱蒸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了烛愧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片油宜。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡掂碱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出慎冤,到底是詐尸還是另有隱情疼燥,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布蚁堤,位于F島的核電站醉者,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏披诗。R本人自食惡果不足惜撬即,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望呈队。 院中可真熱鬧剥槐,春花似錦、人聲如沸宪摧。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)几于。三九已至蕊苗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沿彭,已是汗流浹背朽砰。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留喉刘,地道東北人瞧柔。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像饱搏,于是被迫代替她去往敵國(guó)和親非剃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

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