《設(shè)計(jì)模式》中定義:
Builder模式的緣起: 假設(shè)創(chuàng)建游戲中的一個(gè)房屋House設(shè)施,該房屋的構(gòu)建由幾部分組成,且各個(gè)部分富于變化。如果使用最直觀的設(shè)計(jì)方法,每一個(gè)房屋部分的變化,都將導(dǎo)致房屋構(gòu)建的重新修正.....
動(dòng)機(jī)(Motivation): 在軟件系統(tǒng)中,有時(shí)候面臨一個(gè)"復(fù)雜對象"的創(chuàng)建工作,其通常由各個(gè)部分的子對象用一定算法構(gòu)成;由于需求的變化,這個(gè)復(fù)雜對象的各個(gè)部分經(jīng)常面臨著劇烈的變化,但是將它們組合到一起的算法卻相對穩(wěn)定。
如何應(yīng)對種變化呢?如何提供一種"封裝機(jī)制"來隔離出"復(fù)雜對象的各個(gè)部分"的變化,從而保持系統(tǒng)中的"穩(wěn)定構(gòu)建算法"不隨需求的改變而改變?
意圖(Intent): 將一個(gè)復(fù)雜對象的構(gòu)建與其表示相分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
UML 表示如下:
|
Builder模式 |
這里的Builder是一個(gè)抽象類,不是接口,為了共用一些屬性和代碼,把稍微變化的部分讓子類來實(shí)現(xiàn)(顯然Builder 和 ConcreteOneProduct、ConcreteTwoProduct組成了個(gè)模板模式)。
先看建造者,一個(gè)抽象類,提供一些公用實(shí)現(xiàn)(Builder.java):
/** * 一個(gè)抽象來來替代接口 * * @author yongboy@gmail.com * @date 2010-10-26 * @version 1.0 */ public abstract class Builder { protected Product product = null;
public Builder() { product = new Product(); }
/** * 產(chǎn)生描述內(nèi)容 */ public abstract void genDesc(String desc);
/** * 繪制三角形 */ public abstract void genTriangle(int len);
/** * 輸出最終產(chǎn)生的產(chǎn)品 * * @return */ public Product getProduct() { return product; } } |
一個(gè)實(shí)現(xiàn),主要是繪制三角形:
public class ConcreteOneBuilder extends Builder {
@Override public void genDesc(String desc) { product.setDesc(desc); }
@Override public void genTriangle(int len) { StringBuilder sb = new StringBuilder(); for (int i = 1; i < len; i++) { for (int j = 0; j < i; j++) { sb.append(" *"); } sb.append("\n"); }
product.setContent(sb.toString()); } } |
第二個(gè)實(shí)現(xiàn):
public class ConcreteTwoBuilder extends Builder {
@Override public void genDesc(String desc) { product.setDesc(desc); }
@Override public void genTriangle(int len) { StringBuilder sb = new StringBuilder();
for (int i = len; i > 0; i--) { int spaceNum = len - i;
for (int j = 0; j < spaceNum; j++) { sb.append(" "); } for (int j = 0; j < i; j++) { sb.append(" *"); }
sb.append("\n"); }
product.setContent(sb.toString()); } } |
產(chǎn)品定義:
/** * 一個(gè)有關(guān)三角的產(chǎn)品 * * @author yongboy@gmail.com * @date 2010-10-26 * @version 1.0 */ public class Product implements Serializable { private final static long serialVersionUID = 23536326475869L;
/** * 當(dāng)前產(chǎn)品的描述 */ private String desc;
/** * 當(dāng)前產(chǎn)品的詳細(xì)內(nèi)容 */ private String content;
public Product() { }
public String getDesc() { return desc; }
public void setDesc(String desc) { this.desc = desc; }
public String getContent() { return content; }
public void setContent(String content) { this.content = content; }
public String toString() { return desc + "\n" + content; } } |
導(dǎo)向器,封裝著產(chǎn)品生成的具體過程:
/** * 導(dǎo)向器,封裝產(chǎn)品生生成過程 * * @author yongboy@gmail.com * @date 2010-10-26 * @version 1.0 */ public class Director { private Builder builder; private int MAX = 25; private int MIN = 10;
public Director(Builder builder) { this.builder = builder; }
public void construct() { int len = getNext(); builder.genDesc("產(chǎn)品型號(hào)(" + getFormatNum(len) + "):"); builder.genTriangle(len); }
private int getNext() { return getRandomNum(MIN, MAX); }
private static String getFormatNum(int num) { return String.format("0.%d", num); } /** * 產(chǎn)生兩個(gè)數(shù)之間的隨機(jī)數(shù) * * @param min * @param max * @return */ private int getRandomNum(double min, double max) { return (int) min + (int) (Math.random() * (max - min)); } } |
客戶端代碼調(diào)用方式:
public class Client { public static void main(String[] args) { Builder builder = new ConcreteOneBuilder();
Director director = new Director(builder);
director.construct();
Product product = builder.getProduct();
System.out.println(product);
System.out.println(); System.out.println("現(xiàn)在輸出第二個(gè)產(chǎn)品:\n"); System.out.println();
builder = new ConcreteTwoBuilder();
director = new Director(builder);
director.construct();
product = builder.getProduct();
System.out.println(product); } } |
輸入如下:
產(chǎn)品型號(hào)(0.23):
*
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
* * * * * * * *
* * * * * * * * *
* * * * * * * * * *
* * * * * * * * * * *
* * * * * * * * * * * *
* * * * * * * * * * * * *
* * * * * * * * * * * * * *
* * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * *
現(xiàn)在輸出第二個(gè)產(chǎn)品:
產(chǎn)品型號(hào)(0.17):
* * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * *
* * * * * * * * * * * * * *
* * * * * * * * * * * * *
* * * * * * * * * * * *
* * * * * * * * * * *
* * * * * * * * * *
* * * * * * * * *
* * * * * * * *
* * * * * * *
* * * * * *
* * * * *
* * * *
* * *
* *
*
每一次運(yùn)行可能生成變形長度都會(huì)變好,這個(gè)變好有導(dǎo)向器進(jìn)行控制著。
源文件下載