創(chuàng)建型設(shè)計(jì)模式--建造者模式

記錄結(jié)構(gòu):

          --1.前言
          --2.實(shí)際問題引入(需求)
          --3.使用建造者模式解決問題
             --3.1建造者模式簡(jiǎn)述
             --3.2建造者模式類圖
             --3.3建造者模式完整解決方案
          --4.建造者模式總結(jié)

1.前言

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

2.實(shí)際問題引入(需求)

游戲角色設(shè)計(jì)
YY軟件公司游戲開發(fā)小組決定開發(fā)一款名為《 YY群俠傳》的網(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ā),并身穿一襲白裙;而“惡魔”極其丑陋,留著光頭并穿一件刺眼的黑衣。
YY公司決定開發(fā)一個(gè)小工具來創(chuàng)建游戲角色,可以創(chuàng)建不同類型的角色并可以靈活增加新的角色。

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

創(chuàng)建型設(shè)計(jì)模式.gif (注:本圖中的游戲角色造型來源于網(wǎng)絡(luò),特此說明)

3.使用建造者模式解決問題

3.1.建造者模式簡(jiǎn)述:

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

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

建造者模式類圖.gif

各組件詳解:

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)部表示并定義它的裝配過程。
Director(指揮者):指揮者又稱為導(dǎo)演類,它負(fù)責(zé)安排復(fù)雜對(duì)象的建造次序,指揮者與抽象建造者之間存在聚合關(guān)系,可以在其 construct() 建造方法中調(diào)用建造者對(duì)象(使用多態(tài),其實(shí)調(diào)用的是具體建造者的對(duì)象)的部件構(gòu)造與裝配方法,完成復(fù)雜對(duì)象的建造。客戶端一般只需要與指揮者進(jìn)行交互,在客戶端確定具體建造者的類型,并實(shí)例化具體建造者對(duì)象(也可以通過配置文件和反射機(jī)制),然后通過指揮者類的構(gòu)造函數(shù)或者 Setter 方法將該對(duì)象(具體建造者)傳入指揮者類中。

3.3建造者模式完整解決方案
YY公司開發(fā)人員決定使用建造者模式來實(shí)現(xiàn)游戲角色的創(chuàng)建,其基本結(jié)構(gòu)如圖所示:

建造者模式解決游戲人物創(chuàng)建結(jié)構(gòu)類圖.gif

在圖中,ActorController 充當(dāng)指揮者,ActorBuilder 充當(dāng)抽象建造者,HeroBuilder、AngelBuilder 和 DevilBuilder 充當(dāng)具體建造者,Actor 充當(dāng)復(fù)雜產(chǎn)品。完整代碼如下所示:

//Actor角色類:復(fù)雜產(chǎn)品,考慮到代碼的可讀性,只列出部分成員屬性,
//且成員屬性的類型均為String,真實(shí)情況下,有些成員屬性的類型需自定義
class Actor
{
       private  String type; //角色類型
       private  String sex; //性別
       private  String face; //臉型
       private  String costume; //服裝
       private  String hairstyle; //發(fā)型

       public  void setType(String type) {
              this.type  = type;
       }
       public  void setSex(String sex) {
              this.sex  = sex;
       }
       public  void setFace(String face) {
              this.face  = face;
       }
       public  void setCostume(String costume) {
              this.costume  = costume;
       }
       public  void setHairstyle(String hairstyle) {
              this.hairstyle  = hairstyle;
       }
       public  String getType() {
              return  (this.type);
       }
       public  String getSex() {
              return  (this.sex);
       }
       public  String getFace() {
              return  (this.face);
       }
       public  String getCostume() {
              return  (this.costume);
       }
       public  String getHairstyle() {
              return  (this.hairstyle);
       }
}

//角色建造器:抽象建造者
abstract class ActorBuilder
{
       protected  Actor actor = new Actor();

       public  abstract void buildType();
       public  abstract void buildSex();
       public  abstract void buildFace();
       public  abstract void buildCostume();
       public  abstract void buildHairstyle();

       //工廠方法,返回一個(gè)完整的游戲角色對(duì)象
       public Actor createActor()
       {
              return actor;
       }
}

//英雄角色建造器:具體建造者
class HeroBuilder extends ActorBuilder
{
       public  void buildType()
       {
              actor.setType("英雄");
       }
       public  void buildSex()
       {
              actor.setSex("男");
       }
       public  void buildFace()
       {
              actor.setFace("英俊");
       }
       public  void buildCostume()
       {
              actor.setCostume("盔甲");
       }
       public  void buildHairstyle()
       {
              actor.setHairstyle("飄逸");
       }    
}

//天使角色建造器:具體建造者
class AngelBuilder extends ActorBuilder
{
       public  void buildType()
       {
              actor.setType("天使");
       }
       public  void buildSex()
       {
              actor.setSex("女");
       }
       public  void buildFace()
       {
              actor.setFace("漂亮");
       }
       public  void buildCostume()
       {
              actor.setCostume("白裙");
       }
       public  void buildHairstyle()
       {
              actor.setHairstyle("披肩長(zhǎng)發(fā)");
       }    
}

//惡魔角色建造器:具體建造者
class DevilBuilder extends ActorBuilder
{
       public  void buildType()
       {
              actor.setType("惡魔");
       }
       public  void buildSex()
       {
              actor.setSex("妖");
       }
       public  void buildFace()
       {
              actor.setFace("丑陋");
       }
       public  void buildCostume()
       {
              actor.setCostume("黑衣");
       }
       public  void buildHairstyle()
       {
              actor.setHairstyle("光頭");
       }    
}

指揮者類 ActorController 定義了 construct() 方法,該方法擁有一個(gè)抽象建造者 ActorBuilder 類型的參數(shù),在該方法內(nèi)部實(shí)現(xiàn)了游戲角色對(duì)象的逐步構(gòu)建,代碼如下所示:

//游戲角色創(chuàng)建控制器:指揮者
class ActorController
{
    //逐步構(gòu)建復(fù)雜產(chǎn)品對(duì)象
       public Actor construct(ActorBuilder ab)
       {
              Actor actor;
              ab.buildType();
              ab.buildSex();
              ab.buildFace();
              ab.buildCostume();
              ab.buildHairstyle();
              actor=ab.createActor();
              return actor;
       }
}

為了提高系統(tǒng)的靈活性和可擴(kuò)展性,我們將具體建造者類的類名存儲(chǔ)在配置文件中,并通過工具類 XMLUtil 來讀取配置文件并反射生成對(duì)象,XMLUtil 類的代碼如下所示:

import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;
class XMLUtil
{
//該方法用于從XML配置文件中提取具體類類名,并返回一個(gè)實(shí)例對(duì)象
       public  static Object getBean()
       {
              try
              {
                     //創(chuàng)建文檔對(duì)象
                     DocumentBuilderFactory  dFactory = DocumentBuilderFactory.newInstance();
                     DocumentBuilder  builder = dFactory.newDocumentBuilder();
                     Document  doc;                                                
                     doc  = builder.parse(new File("config.xml"));

                     //獲取包含類名的文本節(jié)點(diǎn)
                     NodeList  nl = doc.getElementsByTagName("className");
            Node  classNode=nl.item(0).getFirstChild();
            String  cName=classNode.getNodeValue();

            //通過類名生成實(shí)例對(duì)象并將其返回
            Class c=Class.forName(cName);
                 Object obj=c.newInstance();
            return obj;
         }  
         catch(Exception e)
         {
              e.printStackTrace();
              return null;
          }
       }
}

編寫如下客戶端測(cè)試代碼:

class Client {
       public  static void main(String args[])
       {
              ActorBuilder ab; //針對(duì)抽象建造者編程
              ab =  (ActorBuilder)XMLUtil.getBean(); //反射生成具體建造者對(duì)象

         ActorController ac = new  ActorController();
              Actor actor;
              actor = ac.construct(ab); //通過指揮者創(chuàng)建完整的建造者對(duì)象

              String  type = actor.getType();
              System.out.println(type  + "的外觀:");
              System.out.println("性別:" + actor.getSex());
              System.out.println("面容:" + actor.getFace());
              System.out.println("服裝:" + actor.getCostume());
              System.out.println("發(fā)型:" + actor.getHairstyle());
       }
}

編譯并運(yùn)行程序,輸出結(jié)果如下:

天使的外觀:
性別:女
面容:漂亮
服裝:白裙
發(fā)型:披肩長(zhǎng)發(fā)

在建造者模式中,客戶端只需實(shí)例化指揮者類,指揮者類針對(duì)抽象建造者編程,客戶端根據(jù)需要傳入具體的建造者類型,指揮者將指導(dǎo)具體建造者一步一步構(gòu)造一個(gè)完整的產(chǎn)品(逐步調(diào)用具體建造者的 buildX() 方法),相同的構(gòu)造過程可以創(chuàng)建完全不同的產(chǎn)品。在游戲角色實(shí)例中,如果需要更換角色,只需要修改配置文件,更換具體角色建造者類即可;如果需要增加新角色,可以增加一個(gè)新的具體角色建造者類作為抽象角色建造者的子類,再修改配置文件即可,原有代碼無須修改,完全符合“開閉原則”。

4.建造者模式總結(jié)

建造者模式的核心在于如何一步步構(gòu)建一個(gè)包含多個(gè)組成部件的完整對(duì)象,使用相同的構(gòu)建過程構(gòu)建不同的產(chǎn)品,在軟件開發(fā)中,如果我們需要?jiǎng)?chuàng)建復(fù)雜對(duì)象并希望系統(tǒng)具備很好的靈活性和可擴(kuò)展性可以考慮使用建造者模式。

主要優(yōu)點(diǎn)

建造者模式的主要優(yōu)點(diǎn)如下:

(1) 在建造者模式中,客戶端不必知道產(chǎn)品內(nèi)部組成的細(xì)節(jié),將產(chǎn)品本身與產(chǎn)品的創(chuàng)建過程解耦,使得相同的創(chuàng)建過程可以創(chuàng)建不同的產(chǎn)品對(duì)象。

(2) 每一個(gè)具體建造者都相對(duì)獨(dú)立,而與其他的具體建造者無關(guān),因此可以很方便地替換具體建造者或增加新的具體建造者,用戶使用不同的具體建造者即可得到不同的產(chǎn)品對(duì)象。由于指揮者類針對(duì)抽象建造者編程,增加新的具體建造者無須修改原有類庫(kù)的代碼,系統(tǒng)擴(kuò)展方便,符合“開閉原則”

(3) 可以更加精細(xì)地控制產(chǎn)品的創(chuàng)建過程。將復(fù)雜產(chǎn)品的創(chuàng)建步驟分解在不同的方法中,使得創(chuàng)建過程更加清晰,也更方便使用程序來控制創(chuàng)建過程。

主要缺點(diǎn)

建造者模式的主要缺點(diǎn)如下:

(1) 建造者模式所創(chuàng)建的產(chǎn)品一般具有較多的共同點(diǎn),其組成部分相似,如果產(chǎn)品之間的差異性很大,例如很多組成部分都不相同,不適合使用建造者模式,因此其使用范圍受到一定的限制。

(2) 如果產(chǎn)品的內(nèi)部變化復(fù)雜,可能會(huì)導(dǎo)致需要定義很多具體建造者類來實(shí)現(xiàn)這種變化,導(dǎo)致系統(tǒng)變得很龐大,增加系統(tǒng)的理解難度和運(yùn)行成本。

適用場(chǎng)景

在以下情況下可以考慮使用建造者模式:

(1) 需要生成的產(chǎn)品對(duì)象有復(fù)雜的內(nèi)部結(jié)構(gòu),這些產(chǎn)品對(duì)象通常包含多個(gè)成員屬性。

(2) 需要生成的產(chǎn)品對(duì)象的屬性相互依賴,需要指定其生成順序。

(3) 對(duì)象的創(chuàng)建過程獨(dú)立于創(chuàng)建該對(duì)象的類。在建造者模式中通過引入了指揮者類,將創(chuàng)建過程封裝在指揮者類中,而不在建造者類和客戶類中。

(4) 隔離復(fù)雜對(duì)象的創(chuàng)建和使用,并使得相同的創(chuàng)建過程可以創(chuàng)建不同的產(chǎn)品。

特此說明:文章引用于極客學(xué)院--創(chuàng)建型設(shè)計(jì)模式

博客搬家:大坤的個(gè)人博客
歡迎評(píng)論哦~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評(píng)論 6 546
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,814評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評(píng)論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評(píng)論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,779評(píng)論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,109評(píng)論 1 330
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評(píng)論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,287評(píng)論 0 291
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,799評(píng)論 1 338
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,515評(píng)論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,750評(píng)論 1 375
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,933評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評(píng)論 1 296
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,492評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,703評(píng)論 2 380

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