設計模式解密(6) - 建造者模式(生成器模式)

大學生就業(yè)培訓,高中生培訓,在職人員轉行培訓,企業(yè)團訓

1、簡介

定義:將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創(chuàng)建不同的表示。

分解一下定義:

  1、復雜對象的表示;
  2、復雜對象的構建過程;
  3、可分離的通用構建過程,也適用于其它復雜對象的表示;
  4、適用于一些基本部件不會變,而其組合經常變化的時候。

英文:Builder

類型:創(chuàng)建類模式

 2、原理及組成

:類圖

大學生就業(yè)培訓,高中生培訓,在職人員轉行培訓,企業(yè)團訓

四個要素

  產品類:一般是一個較為復雜的對象,也就是說創(chuàng)建對象的過程比較復雜,一般會有比較多的代碼量。在本類圖中,產品類是一個具體的類,而非抽象類。

      實際編程中,產品類可以是由一個抽象類與它的不同實現組成,也可以是由多個抽象類與他們的實現組成。

  抽象建造者:引入抽象建造者的目的,是為了將建造的具體過程交與它的子類來實現。這樣更容易擴展。

        一般至少會有兩個抽象方法,一個用來建造產品,一個是用來返回產品。

  建造者:實現抽象類的所有未實現的方法,具體來說一般是兩項任務:組建產品;返回組建好的產品。

  導演類:負責調用適當的建造者來組建產品,導演類一般不與產品類發(fā)生依賴關系,與導演類直接交互的是建造者類。

      一般來說,導演類被用來封裝程序中易變的部分。

 

其中最重要的兩個部分

  1、一個部分是Builder接口,這里是定義了如何構建各個部件,也就是知道每個部件功能如何實現 
  2、另外一個部分是Director,Director是知道如何組合來構建產品,也就是說Director負責整體的構建算法,而且通常是分步驟地來執(zhí)行,也就是說如何組裝這些部件。

不管如何變化,建造模式都存在這么兩個部分,一個部分是部件構造。另一個部分是整體構建的算法。 
再直白點說,建造模式的重心在于分離構建算法和具體的構造實現,從而使得構建算法可以重用。具體的構造實現可以很方便地擴展和切換,從而可以靈活地組合來構造出不同的產品對象。

 3、實例引入

背景:模擬生產各種筆(這里假設筆的零件生產是有順序的:筆芯 -> 筆殼 -> 組裝)

創(chuàng)建抽象產品類 -- 筆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.designpattern.builder;
/**
 * 筆  -- 抽象產品類
*/
public abstract class Pen {
    /**筆芯**/
    private String cartridge;
    /**外殼**/
    private String shell;
     
    public String getCartridge() {
        return cartridge;
    }
    public void setCartridge(String cartridge) {
        this.cartridge = cartridge;
    }
    public String getShell() {
        return shell;
    }
    public void setShell(String shell) {
        this.shell = shell;
    }
}

創(chuàng)建抽象建造者(筆builder) 接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.designpattern.builder;
/**
 * 抽象建造者  -- 筆builder
*/
public abstract interface PenBuilder {
    /**
     * 生產筆芯
     */
    abstract void buildCartridge();
    /**
     * 生產外殼
     */
    abstract void buildShell();
    /**
     * 組裝筆
     */
    abstract Pen buildPen();
}

創(chuàng)建具體產品類(圓珠筆)

1
2
3
4
5
6
7
8
9
package com.designpattern.builder;
/**
 * 具體產品類 -- 圓珠筆
*/
public class BallpointPen extends Pen{
    public BallpointPen(){
        System.out.println("生產組裝圓珠筆");
    }
}

創(chuàng)建具體產品類(畫筆)

1
2
3
4
5
6
7
8
9
package com.designpattern.builder;
/**
 * 具體產品類 -- 畫筆
*/
public class BrushPen extends Pen{
    public BrushPen(){
        System.out.println("生產組裝畫筆");
    }
}

創(chuàng)建建造者(具體)  -- 圓珠筆builder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.designpattern.builder.impl;
 
import com.designpattern.builder.BallpointPen;
import com.designpattern.builder.Pen;
import com.designpattern.builder.PenBuilder;
 
/**
 * 建造者(具體)  -- 圓珠筆builder
*/
public class BallpointPenBuilder implements PenBuilder{
     
    Pen pen;
    public BallpointPenBuilder(){
        pen = new BallpointPen();
    }
     
    @Override
    public void buildCartridge() {
        pen.setCartridge("圓珠筆筆芯");
    }
 
    @Override
    public void buildShell() {
        pen.setShell("圓珠筆外殼");
    }
 
    @Override
    public Pen buildPen() {
        return pen;
    }
 
}

創(chuàng)建建造者(具體)  -- 畫筆builder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.designpattern.builder.impl;
 
import com.designpattern.builder.BrushPen;
import com.designpattern.builder.Pen;
import com.designpattern.builder.PenBuilder;
 
/**
 * 建造者(具體)  -- 畫筆builder
*/
public class BrushPenBuilder implements PenBuilder{
     
    Pen pen;
    public BrushPenBuilder(){
        pen = new BrushPen();
    }
     
    @Override
    public void buildCartridge() {
        pen.setCartridge("畫筆筆芯");
    }
 
    @Override
    public void buildShell() {
        pen.setShell("畫筆外殼");
    }
 
    @Override
    public Pen buildPen() {
        return pen;
    }
 
}

創(chuàng)建導演類  Director

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.designpattern.builder;
/**
 * 導演類  Director
*/
public class PenDirector {
 
    public Pen constructPen(PenBuilder pen_builder){
        //生產筆芯
        pen_builder.buildCartridge();
        //生產外殼
        pen_builder.buildShell();
        //組裝筆
        return pen_builder.buildPen();
    }
}

下面測試一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.designpattern.builder;
 
import com.designpattern.builder.impl.BallpointPenBuilder;
import com.designpattern.builder.impl.BrushPenBuilder;
 
/**
 * 測試
*/
public class Test {
    public static void main(String[] args) {
        PenDirector director = new PenDirector();
        Pen ballpointpen = director.constructPen(new BallpointPenBuilder());
        Pen brushpen = director.constructPen(new BrushPenBuilder());
    }
}

結果:

1
2
生產組裝圓珠筆
生產組裝畫筆

4、解決的問題

筆的種類不止這幾種,還有很多,使用建造者模式可以將一類產品的構建過程和細節(jié)進行封裝(實現代碼的復用)與產品的表示進行分離,即:使用同樣的構建過程可以創(chuàng)建不同的產品;

在各個建造者類,只需定義生產零件方法,具體的生產順序定義在導演類中;

5、優(yōu)缺點

優(yōu)點:

    封裝性很好:使用建造者模式可以有效的封裝變化,在使用建造者模式的場景中,一般產品類和建造者類是比較穩(wěn)定的,因此,將主要的業(yè)務邏輯封裝在導演類中對整體而言可以取得比較好的穩(wěn)定性。

    擴展性很好:建造者模式很容易進行擴展。如果有新的需求,通過實現一個新的建造者類就可以完成,基本上不用修改之前已經測試通過的代碼,因此也就不會對原有功能引入風險。

    可以有效控制細節(jié)風險:由于具體的建造者是獨立的,因此可以對建造者過程逐步細化,而不對其他的模塊產生任何影響。

缺點:

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

  如果產品的內部變化復雜,可能會導致需要定義很多具體建造者類來實現這種變化,導致系統(tǒng)變得很龐大。

6、應用場景

  建造者模式 --- 建造具有具體細節(jié)的產品

  1、需要生成的產品對象有復雜的內部結構,這些產品對象具備共性。

  2、需要生成的產品對象的屬性相互依賴,建造者模式可以強迫生成順序。

  ........

7、與其他模式對比

  我們可以看到,建造者模式與工廠模式是極為相似的,總體上,建造者模式僅僅只比工廠模式多了一個“導演類”的角色。在建造者模式的類圖中,假如把這個導演類看做是最終調用的客戶端,那么圖中剩余的部分就可以看作是一個簡單的工廠模式了。

  這里先回歸一下定義:

      工廠模式:定義一個用于創(chuàng)建對象的接口,讓子類決定實例化哪一個類。工廠方法使一個類的實例化延遲到其子類;

      建造者模式:將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創(chuàng)建不同的表示;   

  與工廠模式相比,建造者模式一般用來創(chuàng)建更為復雜的對象,因為對象的創(chuàng)建過程更為復雜,因此將對象的創(chuàng)建過程獨立出來組成一個新的類——導演類。也就是說,工廠模式是將對象的全部創(chuàng)建過程封裝在工廠類中,由工廠類向客戶端提供最終的產品;而建造者模式中,建造者類一般只提供產品類中各個組件的建造,而將具體建造過程交付給導演類。由導演類負責將各個組件按照特定的規(guī)則組建為產品,然后將組建好的產品交付給客戶端。

  工廠模式一般都是創(chuàng)建一個產品,注重的是把這個產品創(chuàng)建出來就行,只要創(chuàng)建出來,不關心這個產品的組成部分。

  建造者模式也是創(chuàng)建一個產品,但是不僅要把這個產品創(chuàng)建出來,還要關心這個產品的組成細節(jié), 組成過程。

8、總結

  建造者模式最主要功能是基本方法的調用順序安排,也就是這些基本方法已經實現了;

  而工廠方法則重點是創(chuàng)建,你要什么對象就創(chuàng)造一個對象出來,組裝順序則不是他關心的。

  PS:建造模式的關鍵是導演角色,這個角色掌握了零件對象的狀態(tài)和產品的整體組裝藍圖。沒有了這個角色,建造模式就不是建造模式。當然,導演角色可以同時持有很多種藍圖,按照需要給出完全不同的組裝結果。

 

  PS2:源碼地址   https://github.com/JsonShare/DesignPattern/tree/master 

    

如果您覺得閱讀本文對您有幫助,請點一下“推薦”按鈕,您的“推薦”將是我最大的寫作動力! 
如果標題被標記為轉載,轉載請注明原作者地址,詳見引用 
版權聲明,轉載請注明出處:http://www.cnblogs.com/JsonShare

http://www.cnblogs.com/JsonShare/p/7133403.html