鍍金池/ 教程/ Java/ 復(fù)雜對(duì)象的組裝與創(chuàng)建——建造者模式(一)
工廠三兄弟之抽象工廠模式(五)
復(fù)雜對(duì)象的組裝與創(chuàng)建——建造者模式(一)
工廠三兄弟之工廠方法模式(一)
復(fù)雜對(duì)象的組裝與創(chuàng)建——建造者模式(二)
確保對(duì)象的唯一性——單例模式 (二)
工廠三兄弟之簡(jiǎn)單工廠模式(四)
確保對(duì)象的唯一性——單例模式 (一)
工廠三兄弟之工廠方法模式(四)
對(duì)象的克隆——原型模式(一)
工廠三兄弟之抽象工廠模式(二)
工廠三兄弟之工廠方法模式(三)
工廠三兄弟之抽象工廠模式(一)
工廠三兄弟之抽象工廠模式(四)
確保對(duì)象的唯一性——單例模式 (三)
工廠三兄弟之簡(jiǎn)單工廠模式(三)
對(duì)象的克隆——原型模式(二)
復(fù)雜對(duì)象的組裝與創(chuàng)建——建造者模式(三)
對(duì)象的克隆——原型模式(四)
確保對(duì)象的唯一性——單例模式(四)
工廠三兄弟之簡(jiǎn)單工廠模式(一)
工廠三兄弟之簡(jiǎn)單工廠模式(二)
對(duì)象的克隆——原型模式(三)
工廠三兄弟之抽象工廠模式(三)
確保對(duì)象的唯一性——單例模式(五)
工廠三兄弟之工廠方法模式(二)

復(fù)雜對(duì)象的組裝與創(chuàng)建——建造者模式(一)

沒(méi)有人買車會(huì)只買一個(gè)輪胎或者方向盤,大家買的都是一輛包含輪胎、方向盤和發(fā)動(dòng)機(jī)等多個(gè)部件的完整汽車。如何將這些部件組裝成一輛完整的汽車并返回給用戶,這是建造者模式需要解決的問(wèn)題。建造者模式又稱為生成器模式,它是一種較為復(fù)雜、使用頻率也相對(duì)較低的創(chuàng)建型模式。建造者模式為客戶端返回的不是一個(gè)簡(jiǎn)單的產(chǎn)品,而是一個(gè)由多個(gè)部件組成的復(fù)雜產(chǎn)品。

游戲角色設(shè)計(jì)

Sunny 軟件公司游戲開(kāi)發(fā)小組決定開(kāi)發(fā)一款名為《 Sunny 群俠傳》的網(wǎng)絡(luò)游戲,該游戲采用主流的 RPG(Role Playing Game,角色扮演游戲)模式,玩家可以在游戲中扮演虛擬世界中的一個(gè)特定角色,角色根據(jù)不同的游戲情節(jié)和統(tǒng)計(jì)數(shù)據(jù)(如力量、魔法、技能等)具有不同的能力,角色也會(huì)隨著不斷升級(jí)而擁有更加強(qiáng)大的能力。

作為 RPG 游戲的一個(gè)重要組成部分,需要對(duì)游戲角色進(jìn)行設(shè)計(jì),而且隨著該游戲的升級(jí)將不斷增加新的角色。不同類型的游戲角色,其性別、臉型、服裝、發(fā)型等外部特性都有所差異,例如“天使”擁有美麗的面容和披肩的長(zhǎng)發(fā),并身穿一襲白裙;而“惡魔”極其丑陋,留著光頭并穿一件刺眼的黑衣。

Sunny 公司決定開(kāi)發(fā)一個(gè)小工具來(lái)創(chuàng)建游戲角色,可以創(chuàng)建不同類型的角色并可以靈活增加新的角色。

Sunny 公司的開(kāi)發(fā)人員通過(guò)分析發(fā)現(xiàn),游戲角色是一個(gè)復(fù)雜對(duì)象,它包含性別、臉型等多個(gè)組成部分,不同的游戲角色其組成部分有所差異,如圖所示:

http://wiki.jikexueyuan.com/project/design-pattern-creation/images/1333532286_6936.gif" alt="幾種不同的游戲角色造型" /> (注:本圖中的游戲角色造型來(lái)源于網(wǎng)絡(luò),特此說(shuō)明)

無(wú)論是何種造型的游戲角色,它的創(chuàng)建步驟都大同小異,都需要逐步創(chuàng)建其組成部分,再將各組成部分裝配成一個(gè)完整的游戲角色。如何一步步創(chuàng)建一個(gè)包含多個(gè)組成部分的復(fù)雜對(duì)象,建造者模式為解決此類問(wèn)題而誕生。

建造者模式概述

建造者模式是較為復(fù)雜的創(chuàng)建型模式,它將客戶端與包含多個(gè)組成部分(或部件)的復(fù)雜對(duì)象的創(chuàng)建過(guò)程分離,客戶端無(wú)須知道復(fù)雜對(duì)象的內(nèi)部組成部分與裝配方式,只需要知道所需建造者的類型即可。它關(guān)注如何一步一步創(chuàng)建一個(gè)的復(fù)雜對(duì)象,不同的具體建造者定義了不同的創(chuàng)建過(guò)程,且具體建造者相互獨(dú)立,增加新的建造者非常方便,無(wú)須修改已有代碼,系統(tǒng)具有較好的擴(kuò)展性。

建造者模式定義如下:

建造者模式(Builder Pattern):將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示。建造者模式是一種對(duì)象創(chuàng)建型模式。

建造者模式一步一步創(chuàng)建一個(gè)復(fù)雜的對(duì)象,它允許用戶只通過(guò)指定復(fù)雜對(duì)象的類型和內(nèi)容就可以構(gòu)建它們,用戶不需要知道內(nèi)部的具體構(gòu)建細(xì)節(jié)。建造者模式結(jié)構(gòu)如圖所示:

http://wiki.jikexueyuan.com/project/design-pattern-creation/images/1333532291_9501.gif" alt="建造者模式結(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ì)象的建造??蛻舳艘话阒恍枰c指揮者進(jìn)行交互,在客戶端確定具體建造者的類型,并實(shí)例化具體建造者對(duì)象(也可以通過(guò)配置文件和反射機(jī)制),然后通過(guò)指揮者類的構(gòu)造函數(shù)或者 Setter 方法將該對(duì)象傳入指揮者類中。

在建造者模式的定義中提到了復(fù)雜對(duì)象,那么什么是復(fù)雜對(duì)象?簡(jiǎn)單來(lái)說(shuō),復(fù)雜對(duì)象是指那些包含多個(gè)成員屬性的對(duì)象,這些成員屬性也稱為部件或零件,如汽車包括方向盤、發(fā)動(dòng)機(jī)、輪胎等部件,電子郵件包括發(fā)件人、收件人、主題、內(nèi)容、附件等部件,一個(gè)典型的復(fù)雜對(duì)象類代碼示例如下:

class Product  {
       private  String partA; //定義部件,部件可以是任意類型,包括值類型和引用類型
       private  String partB;
       private  String partC;
       //partA的Getter方法和Setter方法省略
       //partB的Getter方法和Setter方法省略
       //partC的Getter方法和Setter方法省略
}  

在抽象建造者類中定義了產(chǎn)品的創(chuàng)建方法和返回方法,其典型代碼如下:

abstract class Builder {
     //創(chuàng)建產(chǎn)品對(duì)象
       protected  Product product=new Product();

       public  abstract void buildPartA();
       public  abstract void buildPartB();
       public  abstract void buildPartC();

     //返回產(chǎn)品對(duì)象
       public  Product getResult() {
              return  product;
       }
}

在抽象類 Builder 中聲明了一系列抽象的 buildPartX() 方法用于創(chuàng)建復(fù)雜產(chǎn)品的各個(gè)部件,具體建造過(guò)程在 ConcreteBuilder 中實(shí)現(xiàn),此外還提供了工廠方法 getResult(),用于返回一個(gè)建造好的完整產(chǎn)品。

在 ConcreteBuilder 中實(shí)現(xiàn)了 buildPartX() 方法,通過(guò)調(diào)用 Product 的 setPartX() 方法可以給產(chǎn)品對(duì)象的成員屬性設(shè)值。不同的具體建造者在實(shí)現(xiàn) buildPartX() 方法時(shí)將有所區(qū)別,如 setPartX() 方法的參數(shù)可能不一樣,在有些具體建造者類中某些 setPartX() 方法無(wú)須實(shí)現(xiàn)(提供一個(gè)空實(shí)現(xiàn))。而這些對(duì)于客戶端來(lái)說(shuō)都無(wú)須關(guān)心,客戶端只需知道具體建造者類型即可。

在建造者模式的結(jié)構(gòu)中還引入了一個(gè)指揮者類 Director,該類主要有兩個(gè)作用:一方面它隔離了客戶與創(chuàng)建過(guò)程;另一方面它控制產(chǎn)品的創(chuàng)建過(guò)程,包括某個(gè)buildPartX() 方法是否被調(diào)用以及多個(gè) buildPartX() 方法調(diào)用的先后次序等。指揮者針對(duì)抽象建造者編程,客戶端只需要知道具體建造者的類型,即可通過(guò)指揮者類調(diào)用建造者的相關(guān)方法,返回一個(gè)完整的產(chǎn)品對(duì)象。在實(shí)際生活中也存在類似指揮者一樣的角色,如一個(gè)客戶去購(gòu)買電腦,電腦銷售人員相當(dāng)于指揮者,只要客戶確定電腦的類型,電腦銷售人員可以通知電腦組裝人員給客戶組裝一臺(tái)電腦。指揮者類的代碼示例如下:

class Director {
       private  Builder builder;

       public  Director(Builder builder) {
              this.builder=builder;
       }

       public  void setBuilder(Builder builder) {
              this.builder=builer;
       }

     //產(chǎn)品構(gòu)建與組裝方法
       public Product construct() {
              builder.buildPartA();
              builder.buildPartB();
              builder.buildPartC();
              return builder.getResult();
       }
}

在指揮者類中可以注入一個(gè)抽象建造者類型的對(duì)象,其核心在于提供了一個(gè)建造方法 construct(),在該方法中調(diào)用了 builder 對(duì)象的構(gòu)造部件的方法,最后返回一個(gè)產(chǎn)品對(duì)象。

對(duì)于客戶端而言,只需關(guān)心具體的建造者即可,一般情況下,客戶端類代碼片段如下所示:

……
Builder  builder = new ConcreteBuilder(); //可通過(guò)配置文件實(shí)現(xiàn)
Director director = new  Director(builder);
Product product = director.construct();
……

可以通過(guò)配置文件來(lái)存儲(chǔ)具體建造者類 ConcreteBuilder 的類名,使得更換新的建造者時(shí)無(wú)須修改源代碼,系統(tǒng)擴(kuò)展更為方便。在客戶端代碼中,無(wú)須關(guān)心產(chǎn)品對(duì)象的具體組裝過(guò)程,只需指定具體建造者的類型即可。

建造者模式與抽象工廠模式有點(diǎn)相似,但是建造者模式返回一個(gè)完整的復(fù)雜產(chǎn)品,而抽象工廠模式返回一系列相關(guān)的產(chǎn)品;在抽象工廠模式中,客戶端通過(guò)選擇具體工廠來(lái)生成所需對(duì)象,而在建造者模式中,客戶端通過(guò)指定具體建造者類型并指導(dǎo) Director 類如何去生成對(duì)象,側(cè)重于一步步構(gòu)造一個(gè)復(fù)雜對(duì)象,然后將結(jié)果返回。如果將抽象工廠模式看成一個(gè)汽車配件生產(chǎn)廠,生成不同類型的汽車配件,那么建造者模式就是一個(gè)汽車組裝廠,通過(guò)對(duì)配件進(jìn)行組裝返回一輛完整的汽車。

思考

如果沒(méi)有指揮者類 Director,客戶端將如何構(gòu)建復(fù)雜產(chǎn)品?