### 一、模式定義
造者模式(Builder Pattern):將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
建造者模式是一步一步創建一個復雜的對象,它允許用戶只通過指定復雜對象的類型和內容就可以構建它們,用戶不需要知道內部的具體構建細節。建造者模式屬于對象創建型模式。根據中文翻譯的不同,建造者模式又可以稱為生成器模式。
### 二、模式動機
無論是在現實世界中還是在軟件系統中,都存在一些復雜的對象,它們擁有多個組成部分,如汽車,它包括車輪、方向盤、發送機等各種部件。而對于大多數用戶而言,無須知道這些部件的裝配細節,也幾乎不會使用單獨某個部件,而是使用一輛完整的汽車,可以通過建造者模式對其進行設計與描述,建造者模式可以將部件和其組裝過程分開,一步一步創建一個復雜的對象。用戶只需要指定復雜對象的類型就可以得到該對象,而無須知道其內部的具體構造細節。
在軟件開發中,也存在大量類似汽車一樣的復雜對象,它們擁有一系列成員屬性,這些成員屬性中有些是引用類型的成員對象。而且在這些復雜對象中,還可能存在一些限制條件,如某些屬性沒有賦值則復雜對象不能作為一個完整的產品使用;有些屬性的賦值必須按照某個順序,一個屬性沒有賦值之前,另一個屬性可能無法賦值等。
復雜對象相當于一輛有待建造的汽車,而對象的屬性相當于汽車的部件,建造產品的過程就相當于組合部件的過程。由于組合部件的過程很復雜,因此,這些部件的組合過程往往被“外部化”到一個稱作建造者的對象里,建造者返還給客戶端的是一個已經建造完畢的完整產品對象,而用戶無須關心該對象所包含的屬性以及它們的組裝方式,這就是建造者模式的模式動機。
### 三、模式結構
比較常見的是下面這種只有一個產品的模式結構,大多數的書中也是這樣講的。

從圖中我們可以看出,創建者模式由四部分組成。
- 抽象創建者角色:給出一個抽象接口,以規范產品對象的各個組成成分的建造。一般而言,此接口獨立于應用程序的商業邏輯。模式中直接創建產品對象的是具體創建者角色。具體創建者必須實現這個接口的兩種方法:一是建造方法,比如圖中的buildPart1和buildPart2方法;另一種是結果返回方法,即圖中的getProduct方法。一般來說,產品所包含的零件數目與建造方法的數目相符。換言之,有多少零件,就有多少相應的建造方法。
- 具體創建者角色:他們在應用程序中負責創建產品的實例。這個角色要完成的任務包括:
1、實現抽象創建者所聲明的抽象方法,給出一步一步的完成產品創建實例的操作。 2、在創建完成后,提供產品的實例。
- 導演者角色:這個類調用具體創建者角色以創建產品對象。但是導演者并沒有產品類的具體知識,真正擁有產品類的具體知識的是具體創建者角色。
- 產品角色:產品便是建造中的復雜對象。一般說來,一個系統中會有多于一個的產品類,而且這些產品類并不一定有共同的接口,而完全可以使不相關聯的。
創建者模式的流程是這樣的,客戶端需要創建什么對象實例就創建一個導演類和這個對象的創建者,將創建者傳給導演類,導演類會使用創建者來創建具體的產品。但是導演類并不清楚產品究竟是怎么創建出來的,產品的實際創建過程是由具體工廠來負責的,具體工廠在創建時也是分為若干步驟,比如圖中表示出了兩個部分part1和part2,分別對應產品的兩個零件,具體工廠就是通過一點一點的創建產品的每個部分最后組成產品。
在實際的應用中不可能只用創建者模式創建一種產品,下邊就以兩種產品為例討論一下怎么樣通過創建者模式創建多種產品。

要想使用創建者模式創建多種產品的話,有一個隱含的前提,那就是這些產品有共同的特性,也就是說可以用共同的接口實現。比如我們的上圖中Product1和Product2都繼承自AbstractProduct,并且這兩種產品都有part1和part2兩部分,但是每種產品的part1和part2實現方式不同,這時就可以使用創建者模式。除了這一點外,另外需要主要的是在AbsractBuilder中返回的是產品的共同父類,這樣才能滿足多個產品的返回都正常。
可能有人會產生疑問,如果一個產品有3部分組成而另一個產品由2部分組成,是不是就不能使用創建者模式了呢。不是的,同樣可以使用創建者模式,在產品類中定義三部分,在只有2不部分的產品中不屬于自己的哪一部分設為空就好了。
### 四、實例分析
前邊我們講了土豪坐車的例子,但是還沒講土豪的汽車是怎么生產出來的,我們知道汽車的生產過程是很復雜的,同時汽車又是由很多組建組成的。但是土豪不需要知道汽車是怎樣制造出來的,其中的零件怎么安裝,按照什么順序安裝等等,這些土豪都不需要知道。所以我們應該將汽車生產這一部分移到一個特定的地方。
可能有人會想我們可以在Audi類的構造方法中進行零件的生產和拼裝,但是這樣做的話Benz車和Bmw車都需要在構造方法中加入制造零件和拼裝組建的功能。一是顯得的很麻煩,因為每個類都增加了一塊很復雜的代碼,同時我們應當認識到,雖然Audi和Bnez的制造細節不同但是大體的流程是差不多的,大家都由引擎,輪胎,方向盤等組成,這些相似的代碼在不同的類中重復是很不優雅的。
像這種產品的組成部分相同但是具體生產細節不同的情況特別適合使用創建者模式。
~~~
package com.designpattern.builder;
/**
* 抽象建造類,提供創建產品的共同接口,不同的產品可以有自己的具體實現
* @author
*
*/
public abstract class AbstractBuilder {
/**
* 創建引擎
*/
public abstract void buildEngine();
/**
* 創建車玻璃
*/
public abstract void buildGlass();
/**
* 創建方向盤
*/
public abstract void buildSteeringWheel();
/**
* 返回創建好的產品,為了兼容所有的產品,返回的類型定為共同的父類
* @return
*/
public abstract Car getCar();
}
~~~
~~~
package com.designpattern.builder;
/**
* Audi的具體創建者
* @author xingjiarong
*
*/
public class AudiBuilder extends AbstractBuilder{
/**
* 創建一個各部分都為空的對象
*/
Audi audi = new Audi();
/**
* 創建各個部分
*/
public void buildEngine() {
audi.engine = "AudiEngine";
}
public void buildGlass() {
audi.glass = 3.5;
}
public void buildSteeringWheel() {
audi.steeringWheel = "AudiSteeringWheel";
}
/**
* 返回創建好的對象
*/
public Car getCar() {
return audi;
}
}
~~~
~~~
package com.designpattern.builder;
/**
* 導演類,根據按照產品的建造和組裝順序組裝產品
* @author xingjiarong
*
*/
public class Director {
private AbstractBuilder build;
public Director(AbstractBuilder build){
this.build = build;
}
/***
* 組成產品的方法,組成的過程可能是有順序的
* @return
*/
public Car construct(){
build.buildSteeringWheel();
build.buildGlass();
build.buildEngine();
return build.getCar();
}
}
~~~
~~~
package com.designpattern.builder;
public abstract class Car {
/**
* 汽車引擎,實際應用中應該是一個對象,這里用字符串來表示
*/
public String engine;
/**
* 汽車玻璃,不同的汽車大小不一樣,需要根據汽車的型號計算
*/
public double glass;
/**
* 汽車方向盤
*/
public String steeringWheel;
public abstract void drive();
}
~~~
~~~
package com.designpattern.builder;
public class Main {
public static void main(String[] args) throws Exception {
/**
* 創建導演類和Audi的建造者
*/
AudiBuilder build = new AudiBuilder();
Director director = new Director(build);
/**
* 利用導演類獲得汽車而不是自己獲得汽車
*/
Car car = director.construct();
//開車
car.drive();
}
}
~~~
Audi沒有變化,Benz車的代碼和Audi車的代碼是相似的,不再貼具體的代碼,最后會附上源碼。
### 五、模式優點
- 在建造者模式中, 客戶端不必知道產品內部組成的細節,將產品本身與產品的創建過程解耦,使得相同的創建過程可以創建不同的產品對象。
- 每一個具體建造者都相對獨立,而與其他的具體建造者無關,因此可以很方便地替換具體建造者或增加新的具體建造者,用戶使用不同的具體建造者即可得到不同的產品對象。
- 可以更加精細地控制產品的創建過程 。將復雜產品的創建步驟分解在不同的方法中,使得創建過程更加清晰,也更方便使用程序來控制創建過程。
- 增加新的具體建造者無須修改原有類庫的代碼,指揮者類針對抽象建造者類編程,系統擴展方便,符合“開閉原則”。
### 六、模式缺點
- 建造者模式所創建的產品一般具有較多的共同點,其組成部分相似,如果產品之間的差異性很大,則不適合使用建造者模式,因此其使用范圍受到一定的限制。
- 如果產品的內部變化復雜,可能會導致需要定義很多具體建造者類來實現這種變化,導致系統變得很龐大。
### 七、適用場景
- 需要生成的產品對象有復雜的內部結構,這些產品對象通常包含多個成員屬性。
- 需要生成的產品對象的屬性相互依賴,需要指定其生成順序。
- 對象的創建過程獨立于創建該對象的類。在建造者模式中引入了指揮者類,將創建過程封裝在指揮者類中,而不在建造者類中。
- 隔離復雜對象的創建和使用,并使得相同的創建過程可以創建不同的產品。
### 八、與抽象工廠模式的區別
在抽象工廠模式中,每一次工廠對象被調用時都會返回一個完整的產品對象,而客戶端有可能會決定把這些產品組裝成一個更大更復雜的產品,也有可能不會。建造類則不同,它一點一點的建造出一個復雜的產品,而這個產品的組裝過程就發生在創建者角色內部。建造者的客戶端拿到的是一個完整的最后產品。
換言之,抽象工廠模式處在更加具體的尺度上,而建造者模式處在更加宏觀的尺度上。一個系統可以由一個建造模式和一個抽象工廠模式組成,客戶端通過調用這個創建角色,間接地調用另一個抽象工廠模式的工廠角色。工廠模式返回不同產品族的零件,而建造者模式則把他們組裝起來。
源碼下載:[http://download.csdn.net/detail/xingjiarong/9299923](http://download.csdn.net/detail/xingjiarong/9299923)
- 前言
- 設計原則(一)"開-閉"原則(OCP)
- 設計原則(二)里氏替換原則(LSP)
- 設計原則(三)組合復用原則
- 設計原則(四)依賴倒置原則(DIP)
- 設計模式(一)簡單工廠模式
- 設計模式(二)工廠方法模式
- 設計模式(三)抽象工廠模式
- 設計模式(四)單例模式
- 設計模式(五)創建者模式(Builder)
- 設計模式(六)原型模式
- 設計模式(七)門面模式(Facade Pattern 外觀模式)
- 設計模式(八)橋梁模式(Bridge)
- 設計模式(九)裝飾模式(Decorator)
- 設計模式(十)適配器模式
- 設計模式(十一)策略模式
- 設計模式(十二)責任鏈模式
- 設計模式之UML(一)類圖以及類間關系(泛化 、實現、依賴、關聯、聚合、組合)
- 設計模式之橋梁模式和策略模式的區別