天天看點

複雜對象的組裝與建立——建造者模式(一)

      沒有人買車會隻買一個輪胎或者方向盤,大家買的都是一輛包含輪胎、方向盤和發動機等多個部件的完整汽車。如何将這些部件組裝成一輛完整的汽車并傳回給使用者,這是建造者模式需要解決的問題。建造者模式又稱為生成器模式,它是一種較為複雜、使用頻率也相對較低的建立型模式。建造者模式為用戶端傳回的不是一個簡單的産品,而是一個由多個部件組成的複雜産品。

8.1 遊戲角色設計

Sunny軟體公司遊戲開發小組決定開發一款名為《Sunny群俠傳》的網絡遊戲,該遊戲采用主流的RPG(Role Playing Game,角色扮演遊戲)模式,玩家可以在遊戲中扮演虛拟世界中的一個特定角色,角色根據不同的遊戲情節和統計資料(如力量、魔法、技能等)具有不同的能力,角色也會随着不斷更新而擁有更加強大的能力。

作為RPG遊戲的一個重要組成部分,需要對遊戲角色進行設計,而且随着該遊戲的更新将不斷增加新的角色。不同類型的遊戲角色,其性别、臉型、服裝、發型等外部特性都有所差異,例如“天使”擁有美麗的面容和披肩的長發,并身穿一襲白裙;而“惡魔”極其醜陋,留着光頭并穿一件刺眼的黑衣。

Sunny公司決定開發一個小工具來建立遊戲角色,可以建立不同類型的角色并可以靈活增加新的角色。

       Sunny公司的開發人員通過分析發現,遊戲角色是一個複雜對象,它包含性别、臉型等多個組成部分,不同的遊戲角色其組成部分有所差異,如圖8-1所示:

複雜對象的組裝與建立——建造者模式(一)

圖8-1 幾種不同的遊戲角色造型

(注:本圖中的遊戲角色造型來源于網絡,特此說明)

       無論是何種造型的遊戲角色,它的建立步驟都大同小異,都需要逐漸建立其組成部分,再将各組成部分裝配成一個完整的遊戲角色。如何一步步建立一個包含多個組成部分的複雜對象,建造者模式為解決此類問題而誕生。

8.2 建造者模式概述

      建造者模式是較為複雜的建立型模式,它将用戶端與包含多個組成部分(或部件)的複雜對象的建立過程分離,用戶端無須知道複雜對象的内部組成部分與裝配方式,隻需要知道所需建造者的類型即可。它關注如何一步一步建立一個的複雜對象,不同的具體建造者定義了不同的建立過程,且具體建造者互相獨立,增加新的建造者非常友善,無須修改已有代碼,系統具有較好的擴充性。

      建造者模式定義如下:

建造者模式(Builder Pattern):将一個複雜對象的建構與它的表示分離,使得同樣的建構過程可以建立不同的表示。建造者模式是一種對象建立型模式。

      建造者模式一步一步建立一個複雜的對象,它允許使用者隻通過指定複雜對象的類型和内容就可以建構它們,使用者不需要知道内部的具體建構細節。建造者模式結構如圖8-2所示:

複雜對象的組裝與建立——建造者模式(一)

圖8-2 建造者模式結構圖

      在建造者模式結構圖中包含如下幾個角色:

● Builder(抽象建造者):它為建立一個産品Product對象的各個部件指定抽象接口,在該接口中一般聲明兩類方法,一類方法是buildPartX(),它們用于建立複雜對象的各個部件;另一類方法是getResult(),它們用于傳回複雜對象。Builder既可以是抽象類,也可以是接口。

●ConcreteBuilder(具體建造者):它實作了Builder接口,實作各個部件的具體構造和裝配方法,定義并明确它所建立的複雜對象,也可以提供一個方法傳回建立好的複雜産品對象。

●Product(産品角色):它是被建構的複雜對象,包含多個組成部件,具體建造者建立該産品的内部表示并定義它的裝配過程。

● Director(指揮者):指揮者又稱為導演類,它負責安排複雜對象的建造次序,指揮者與抽象建造者之間存在關聯關系,可以在其construct()建造方法中調用建造者對象的部件構造與裝配方法,完成複雜對象的建造。用戶端一般隻需要與指揮者進行互動,在用戶端确定具體建造者的類型,并執行個體化具體建造者對象(也可以通過配置檔案和反射機制),然後通過指揮者類的構造函數或者Setter方法将該對象傳入指揮者類中。

      在建造者模式的定義中提到了複雜對象,那麼什麼是複雜對象?簡單來說,複雜對象是指那些包含多個成員屬性的對象,這些成員屬性也稱為部件或零件,如汽車包括方向盤、發動機、輪胎等部件,電子郵件包括發件人、收件人、主題、内容、附件等部件,一個典型的複雜對象類代碼示例如下:

class Product  {

       private  String partA; //定義部件,部件可以是任意類型,包括值類型和引用類型

       private  String partB;

       private  String partC;

       //partA的Getter方法和Setter方法省略

       //partB的Getter方法和Setter方法省略

       //partC的Getter方法和Setter方法省略

}

      在抽象建造者類中定義了産品的建立方法和傳回方法,其典型代碼如下:

abstract class Builder {

     //建立産品對象

       protected  Product product=new Product();

       public  abstract void buildPartA();

       public  abstract void buildPartB();

       public  abstract void buildPartC();

     //傳回産品對象

       public  Product getResult() {

              return  product;

       }

}

      在抽象類Builder中聲明了一系列抽象的buildPartX()方法用于建立複雜産品的各個部件,具體建造過程在ConcreteBuilder中實作,此外還提供了工廠方法getResult(),用于傳回一個建造好的完整産品。

      在ConcreteBuilder中實作了buildPartX()方法,通過調用Product的setPartX()方法可以給産品對象的成員屬性設值。不同的具體建造者在實作buildPartX()方法時将有所差別,如setPartX()方法的參數可能不一樣,在有些具體建造者類中某些setPartX()方法無須實作(提供一個空實作)。而這些對于用戶端來說都無須關心,用戶端隻需知道具體建造者類型即可。

      在建造者模式的結構中還引入了一個指揮者類Director,該類主要有兩個作用:一方面它隔離了客戶與建立過程;另一方面它控制産品的建立過程,包括某個buildPartX()方法是否被調用以及多個buildPartX()方法調用的先後次序等。指揮者針對抽象建造者程式設計,用戶端隻需要知道具體建造者的類型,即可通過指揮者類調用建造者的相關方法,傳回一個完整的産品對象。在實際生活中也存在類似指揮者一樣的角色,如一個客戶去購買電腦,電腦銷售人員相當于指揮者,隻要客戶确定電腦的類型,電腦銷售人員可以通知電腦組裝人員給客戶組裝一台電腦。指揮者類的代碼示例如下:

class Director {

       private  Builder builder;

       public  Director(Builder builder) {

              this.builder=builder;

       }

       public  void setBuilder(Builder builder) {

              this.builder=builer;

       }

     //産品建構與組裝方法

       public Product construct() {

              builder.buildPartA();

              builder.buildPartB();

              builder.buildPartC();

              return builder.getResult();

       }

}

      在指揮者類中可以注入一個抽象建造者類型的對象,其核心在于提供了一個建造方法construct(),在該方法中調用了builder對象的構造部件的方法,最後傳回一個産品對象。

      對于用戶端而言,隻需關心具體的建造者即可,一般情況下,用戶端類代碼片段如下所示:

……

Builder  builder = new ConcreteBuilder(); //可通過配置檔案實作

Director director = new  Director(builder);

Product product = director.construct();

……

      可以通過配置檔案來存儲具體建造者類ConcreteBuilder的類名,使得更換新的建造者時無須修改源代碼,系統擴充更為友善。在用戶端代碼中,無須關心産品對象的具體組裝過程,隻需指定具體建造者的類型即可。

      建造者模式與抽象工廠模式有點相似,但是建造者模式傳回一個完整的複雜産品,而抽象工廠模式傳回一系列相關的産品;在抽象工廠模式中,用戶端通過選擇具體工廠來生成所需對象,而在建造者模式中,用戶端通過指定具體建造者類型并指導Director類如何去生成對象,側重于一步步構造一個複雜對象,然後将結果傳回。如果将抽象工廠模式看成一個汽車配件生産廠,生成不同類型的汽車配件,那麼建造者模式就是一個汽車組裝廠,通過對配件進行組裝傳回一輛完整的汽車。

思考

如果沒有指揮者類Director,用戶端将如何建構複雜産品?

【作者:劉偉 http://blog.csdn.net/lovelion】