《设计模式》中定义:
Builder模式的缘起: 假设创建游戏中的一个房屋House设施,该房屋的构建由几部分组成,且各个部分富于变化。如果使用最直观的设计方法,每一个房屋部分的变化,都将导致房屋构建的重新修正.....
动机(Motivation): 在软件系统中,有时候面临一个"复杂对象"的创建工作,其通常由各个部分的子对象用一定算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合到一起的算法却相对稳定。
如何应对种变化呢?如何提供一种"封装机制"来隔离出"复杂对象的各个部分"的变化,从而保持系统中的"稳定构建算法"不随需求的改变而改变?
意图(Intent): 将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
UML 表示如下:
|
Builder模式 |
这里的Builder是一个抽象类,不是接口,为了共用一些属性和代码,把稍微变化的部分让子类来实现(显然Builder 和 ConcreteOneProduct、ConcreteTwoProduct组成了个模板模式)。
先看建造者,一个抽象类,提供一些公用实现(Builder.java):
/** * 一个抽象来来替代接口 * * @author yongboy@gmail.com * @date 2010-10-26 * @version 1.0 */ public abstract class Builder { protected Product product = null;
public Builder() { product = new Product(); }
/** * 产生描述内容 */ public abstract void genDesc(String desc);
/** * 绘制三角形 */ public abstract void genTriangle(int len);
/** * 输出最终产生的产品 * * @return */ public Product getProduct() { return product; } } |
一个实现,主要是绘制三角形:
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()); } } |
第二个实现:
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()); } } |
产品定义:
/** * 一个有关三角的产品 * * @author yongboy@gmail.com * @date 2010-10-26 * @version 1.0 */ public class Product implements Serializable { private final static long serialVersionUID = 23536326475869L;
/** * 当前产品的描述 */ private String desc;
/** * 当前产品的详细内容 */ 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; } } |
导向器,封装着产品生成的具体过程:
/** * 导向器,封装产品生生成过程 * * @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("产品型号(" + getFormatNum(len) + "):"); builder.genTriangle(len); }
private int getNext() { return getRandomNum(MIN, MAX); }
private static String getFormatNum(int num) { return String.format("0.%d", num); } /** * 产生两个数之间的随机数 * * @param min * @param max * @return */ private int getRandomNum(double min, double max) { return (int) min + (int) (Math.random() * (max - min)); } } |
客户端代码调用方式:
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("现在输出第二个产品:\n"); System.out.println();
builder = new ConcreteTwoBuilder();
director = new Director(builder);
director.construct();
product = builder.getProduct();
System.out.println(product); } } |
输入如下:
产品型号(0.23):
*
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
* * * * * * * *
* * * * * * * * *
* * * * * * * * * *
* * * * * * * * * * *
* * * * * * * * * * * *
* * * * * * * * * * * * *
* * * * * * * * * * * * * *
* * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * *
现在输出第二个产品:
产品型号(0.17):
* * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * *
* * * * * * * * * * * * * *
* * * * * * * * * * * * *
* * * * * * * * * * * *
* * * * * * * * * * *
* * * * * * * * * *
* * * * * * * * *
* * * * * * * *
* * * * * * *
* * * * * *
* * * * *
* * * *
* * *
* *
*
每一次运行可能生成变形长度都会变好,这个变好有导向器进行控制着。
源文件下载