聂永的博客

记录工作/学习的点点滴滴。

建造者模式:导向器封装生成产品的具体步骤

《设计模式》中定义:
Builder模式的缘起:
    假设创建游戏中的一个房屋House设施,该房屋的构建由几部分组成,且各个部分富于变化。如果使用最直观的设计方法,每一个房屋部分的变化,都将导致房屋构建的重新修正.....
动机(Motivation):
    在软件系统中,有时候面临一个"复杂对象"的创建工作,其通常由各个部分的子对象用一定算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合到一起的算法却相对稳定。
    如何应对种变化呢?如何提供一种"封装机制"来隔离出"复杂对象的各个部分"的变化,从而保持系统中的"稳定构建算法"不随需求的改变而改变?
意图(Intent):
    将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
UML 表示如下:
uml2
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 (intmin + (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):
* * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * *
* * * * * * * * * * * * * *
* * * * * * * * * * * * *
* * * * * * * * * * * *
* * * * * * * * * * *
* * * * * * * * * *
* * * * * * * * *
* * * * * * * *
* * * * * * *
* * * * * *
* * * * *
* * * *
* * *
* *
*

每一次运行可能生成变形长度都会变好,这个变好有导向器进行控制着。

源文件下载

posted on 2010-10-26 17:36 nieyong 阅读(334) 评论(0)  编辑  收藏 所属分类: Java


只有注册用户登录后才能发表评论。


网站导航:
 

公告

所有文章皆为原创,若转载请标明出处,谢谢~

新浪微博,欢迎关注:

导航

<2010年10月>
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

统计

常用链接

留言簿(58)

随笔分类(130)

随笔档案(151)

个人收藏

最新随笔

搜索

最新评论

阅读排行榜

评论排行榜