昨晚回到家裏,我爸爸氣沖沖地跟我訴苦,“哎!,幹個裝修容易麼?顧客啥都不懂,還非得規定裝修順序,要先貼地板磚後刷牆,到時候貼好的地磚上全是泥,哪有這麼幹活的?”老爸幹了一輩子的裝修,一切事宜由他全權負責,難免心力憔悴。但是,我仔細想了下這個事情,如果老爸簽訂了一個公司,公司負責接活攬活,規定裝修要求,老爸只負責執行,那不就輕鬆了嗎?於是我就想起了建造者模式。
建造者模式的定義是:將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。它允許用戶通過制定的對象類型和內容來創建他們,但是用戶並不需要知道這個複雜對象是如何構建的,它只需要明白通過這樣做我可以得到一個完整的複雜對象實例。
建造者模式是爲了將構建複雜對象的過程和它的部件解耦。因爲一個複雜的對象,不但有很多大量組成部分,如汽車,有很多部件:車輪方向盤 發動機還有各種小零件等等,部件很多,但遠不止這些,如何將這些部件裝配成一輛汽車,這個裝配過程也很複雜(需要很好的組裝技術),Builder模式就是爲了將部件和組裝過程分開。
建造者模式主要包含四個角色:
Director:指揮者,導演類,構建一個使用Builder接口的對象。它主要是用於創建一個複雜的對象,負責調用適當的建造者來組建產品。它主要有兩個作用,一是:隔離了客戶與對象的生產過程,二是:負責控制產品對象的生產過程。
Builder:抽象建造者。它聲明爲創建一個Product對象的各個部件指定的抽象接口,一般至少會有兩個抽象方法,一個用來建造產品,一個是用來返回產品。
ConcreteBuilder:具體建造者。實現抽象接口,構建和裝配各個部件,按照要求組建產品和返回組建好的產品。
Product:產品角色。一個具體的產品對象。
現在假設老爸上面簽訂了裝修公司,公司負責與客戶對接,按照客戶要求制定裝修的細則和分派裝修人員,然後按期把裝修好的房子提供給顧客。那麼裝修公司就是Director:
package com.pattern.builder;
import java.util.List;
/**
* 裝修公司相當於Director--負責安排builder和對應的裝修次序
* @author
*
*/
public class BuilderCompany {
private Decorator builder;
public BuilderCompany(Decorator builder) {
this.builder = builder;
}
/**
* 公司安排裝修次序-讓builder去裝修房子
* @param sequence
*/
public void decoration(List<String> sequence){
this.builder.setSequence(sequence);//制定裝修順序
this.builder.getNiceHouse();//提供裝修好的房子
}
}
制定一個抽象建造者,提供建造產品和過程的抽象方法:
package com.pattern.builder;
import java.util.ArrayList;
import java.util.List;
/**
* 裝修者--抽象類
* 定義裝修的動作 並根據動作順序返回結果
* @author
*
*/
public abstract class Decorator {
private List<String> sequence = new ArrayList<String>();//裝修順序
protected abstract void designDrawing();//出設計圖
protected abstract void transHydropower();//水電改造
protected abstract void brushWall();//刷牆
protected abstract void stickTiles();//貼地磚
protected abstract NiceHouse getNiceHouse();//得到裝修好的漂亮房子
/**
* 根據裝修公司制定的裝修次序--執行動作
*/
final protected void setDecorateSequence(){
for(String s:sequence){
if(s.equalsIgnoreCase(Sequence.DRAW)){
this.designDrawing();
}else if(s.equalsIgnoreCase(Sequence.POWER)){
this.transHydropower();
}else if(s.equalsIgnoreCase(Sequence.BRUSH)){
this.brushWall();
}else if(s.equalsIgnoreCase(Sequence.TILES)){
this.stickTiles();
}
}
}
/**
* 設置裝修動作順序
* @param sequence
*/
public void setSequence(List<String> sequence) {
this.sequence = sequence;
}
}
上述爲了編程方便,定義了一個裝修順序的常量類:
package com.pattern.builder;
public class Sequence {
public static final String DRAW="draw";//出設計圖
public static final String POWER="power";//水電改造
public static final String BRUSH="brush";//刷牆
public static final String TILES="tiles";//貼地磚
}
然後老爸和其他同事按照公司規定的順序負責裝修,按期交工即可:
package com.pattern.builder;
/**
* 具體建造者A
* @author
*
*/
public class DecoratorZhang extends Decorator{
@Override
protected void designDrawing() {
System.out.println("DecoratorZhang出設計圖...");
}
@Override
protected void transHydropower() {
System.out.println("DecoratorZhang水電改造...");
}
@Override
protected void brushWall() {
System.out.println("DecoratorZhang刷牆...");
}
@Override
protected void stickTiles() {
System.out.println("DecoratorZhang貼地磚...");
}
@Override
public NiceHouse getNiceHouse() {
super.setDecorateSequence();
return new NiceHouse("DecoratorZhang");
}
}
package com.pattern.builder;
/**
* 具體建造者B
* @author
*
*/
public class DecoratorLi extends Decorator{
@Override
protected void designDrawing() {
System.out.println("DecoratorLi出設計圖...");
}
@Override
protected void transHydropower() {
System.out.println("DecoratorLi水電改造...");
}
@Override
protected void brushWall() {
System.out.println("DecoratorLi刷牆...");
}
@Override
protected void stickTiles() {
System.out.println("DecoratorLi貼地磚...");
}
@Override
public NiceHouse getNiceHouse() {
super.setDecorateSequence();
return new NiceHouse("DecoratorLi");
}
}
定義交付的產品類,這裏就是簡單的裝修好的房子:
package com.pattern.builder;
/**
* 相當於建造者模式中的Product
* @author
*
*/
public class NiceHouse {
public NiceHouse(String houseName) {
System.out.println(houseName+"裝修房子煥然一新啦!\n");
}
}
測試類:N天后,顧客來到公司,說我的房子裝修好了嗎?快帶我看看:
package com.pattern.builder;
import java.util.ArrayList;
import java.util.List;
/**
* 測試類 Customer
* @author
*
*/
public class Customer {
public static void main(String[] args){
/**
* 顧客來到裝修公司,說我要裝修兩套房子
* 第一套 你先給我出個設計圖,然後水電改造,刷牆,貼磚
* 第二套 你先給我水電改造,再出設計圖,貼磚,刷牆
* 我們籤個合同吧,按期給我裝修好,BYE BYE
* 簽好合同後,裝修公司設計好兩套房子的裝修順序,並安排老張和老李分別負責執行
*/
//第一套房子
List<String> sequence1=new ArrayList<String>();
sequence1.add(Sequence.DRAW);
sequence1.add(Sequence.POWER);
sequence1.add(Sequence.BRUSH);
sequence1.add(Sequence.TILES);
DecoratorZhang dzhang=new DecoratorZhang();
BuilderCompany c1=new BuilderCompany(dzhang);
c1.decoration(sequence1);
//第二套房子
List<String> sequence2=new ArrayList<String>();
sequence2.add(Sequence.POWER);
sequence2.add(Sequence.DRAW);
sequence2.add(Sequence.TILES);
sequence2.add(Sequence.BRUSH);
DecoratorLi dli=new DecoratorLi();
BuilderCompany c2=new BuilderCompany(dli);
c2.decoration(sequence2);
}
}
可以看到,建造者模式與工廠模式是極爲相似的,建造者模式僅僅只比工廠模式多了一個“導演類”的角色。如果把這個導演類看做是最終調用的客戶端(客戶),那麼圖中剩餘的部分就可以看作是一個簡單的工廠模式了。與工廠模式相比,建造者模式一般用來創建更爲複雜的對象,因爲對象的創建過程更爲複雜,因此將對象的創建過程獨立出來組成一個新的類——導演類。也就是說,工廠模式是將對象的全部創建過程封裝在工廠類中,由工廠類向客戶端提供最終的產品;而建造者模式中,建造者類一般只提供產品類中各個組件的建造,而將具體建造過程交付給導演類。由導演類負責將各個組件按照特定的規則組建爲產品,然後將組建好的產品交付給客戶端。
優點:
1、將複雜產品的創建步驟分解在不同的方法中,使得我們能夠更加精確的控制複雜對象的產生過程。
2、將產品的創建過程與產品本身分離開來,可以使用相同的創建過程來得到不同的產品。
3、每一個具體建造者都相對獨立,具有良好的擴展性,使用不同的具體建造者即可得到不同的產品對象。
4、客戶端無需關心創建產品的具體細節,統一由“導演類”指定生產過程,調用建造者創建產品。
缺點:
1、建造者模式所創建的產品一般具有較多的共同點,其組成部分相似,如果產品之間的差異性很大,則不適合使用建造者模式,因此其使用範圍受到一定的限制。
2、如果產品的內部變化複雜,可能會導致需要定義很多具體建造者類來實現這種變化,導致系統變得很龐大。