`
chjavach
  • 浏览: 461345 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

研磨设计模式 之 生成器模式(Builder)2 ——跟着cc学设计系列

 
阅读更多

8.2  解决方案

8.2.1  生成器模式来解决

用来解决上述问题的一个合理的解决方案就是生成器模式。那么什么是生成器模式呢?

(1)生成器模式定义

 

(2)应用生成器模式来解决的思路

       仔细分析上面的实现,构建每种格式的数据文件的处理过程,这不就是构建过程吗?而每种格式具体的步骤实现,不就相当于是不同的表示吗?因为不同的步骤实现,决定了最终的表现也就不同。也就是说,上面的问题恰好就是生成器模式要解决的问题。

要实现同样的构建过程可以创建不同的表现,那么一个自然的思路就是先把构建过程独立出来,在生成器模式中把它称为指导者,由它来指导装配过程,但是不负责每步具体的实现。当然,光有指导者是不够的,必须要有能具体实现每步的对象,在生成器模式中称这些实现对象为生成器。

       这样一来,指导者就是可以重用的构建过程,而生成器是可以被切换的具体实现。前面的实现中,每种具体的导出文件格式的实现就相当于生成器。

8.2.2  模式结构和说明

生成器模式的结构如图8.1所示。

 

图8.1  生成器模式结构示意图

Builder

       生成器接口,定义创建一个Product对象所需的各个部件的操作。

ConcreteBuilder

       具体的生成器实现,实现各个部件的创建,并负责组装Product对象的各个部件,同时还提供一个让用户获取组装完成后的产品对象的方法。

Director

       指导者,也被称为导向者,主要用来使用Builder接口,以一个统一的过程来构建所需要的Product对象。

Product

       产品,表示被生成器构建的复杂对象,包含多个部件。

8.2.3  生成器模式示例代码

(1)先看看生成器的接口定义,示例代码如下:

/**

 * 生成器接口,定义创建一个产品对象所需的各个部件的操作

 */

public interface Builder {

    /**

     * 示意方法,构建某个部件

     */

    public void buildPart();

}

(2)再看看具体的生成器实现,示例代码如下:

/**

 * 具体的生成器实现对象

 */

public class ConcreteBuilder implements Builder {

    /**

     * 生成器最终构建的产品对象

     */

    private Product resultProduct;

    /**

     * 获取生成器最终构建的产品对象

     * @return 生成器最终构建的产品对象

     */

    public Product getResult() {

       return resultProduct;

    }

 

    public void buildPart() {

       //构建某个部件的功能处理

    }

}

(3)看看相应的产品对象的接口示意,示例代码如下:

/**

 * 被构建的产品对象的接口

 */

public interface Product {

    //定义产品的操作

}

(4)再来看看指导者的实现示意,示例代码如下:

/**

 * 指导者,指导使用生成器的接口来构建产品的对象

 */

public class Director {

    /**

     * 持有当前需要使用的生成器对象

     */

    private Builder builder;

 

    /**

     * 构造方法,传入生成器对象

     * @param builder 生成器对象

     */

    public Director(Builder builder) {

       this.builder = builder;

    }

 

    /**

     * 示意方法,指导生成器构建最终的产品对象

     */

    public void construct() {

       //通过使用生成器接口来构建最终的产品对象

       builder.buildPart();

    }

}

8.2.4  使用生成器模式重写示例

       要使用生成器模式来重写示例,重要的任务就是要把指导者和生成器接口定义出来。指导者就是用来执行那四个步骤的对象,而生成器是用来实现每种格式下,对于每个步骤的具体实现的对象。

       按照生成器模式重写示例的结构如图8.2所示:

 

图8.2  生成器模式重写示例的结构示意图

下面还是一起来看看代码,会比较清楚。

(1)前面示例中的三个数据模型对象还继续沿用,这里就不去赘述了。

(2)先来看看定义的Builder接口,主要是把导出各种格式文件的处理过程的步骤定义出来,每个步骤负责构建最终导出文件的一部分。示例代码如下:

/**

 * 生成器接口,定义创建一个输出文件对象所需的各个部件的操作

 */

public interface Builder {

    /**

     * 构建输出文件的Header部分

     * @param ehm 文件头的内容

     */

    public void buildHeader(ExportHeaderModel ehm);

    /**

     * 构建输出文件的Body部分

     * @param mapData 要输出的数据的内容

     */

    public void buildBody(

Map<String,Collection<ExportDataModel>> mapData);

    /**

     * 构建输出文件的Footer部分

     * @param efm 文件尾的内容

     */

    public void buildFooter(ExportFooterModel efm);

}

(3)接下来看看具体的生成器实现,其实就是把原来示例中,写在一起的实现,分拆成多个步骤实现了,先看看导出数据到文本文件的生成器实现,示例代码如下:

/**

 * 实现导出数据到文本文件的的生成器对象

 */

public class TxtBuilder implements Builder {

    /**

     * 用来记录构建的文件的内容,相当于产品

     */

    private StringBuffer buffer = new StringBuffer();

 

    public void buildBody(

Map<String, Collection<ExportDataModel>> mapData) {

       for(String tblName : mapData.keySet()){

           //先拼接表名称

           buffer.append(tblName+"\n");

           //然后循环拼接具体数据

           for(ExportDataModel edm : mapData.get(tblName)){

              buffer.append(edm.getProductId()+","

+edm.getPrice()+","+edm.getAmount()+"\n");

           }

       }

    }

    public void buildFooter(ExportFooterModel efm) {

       buffer.append(efm.getExportUser());

    }

    public void buildHeader(ExportHeaderModel ehm) {

       buffer.append(ehm.getDepId()+","

+ehm.getExportDate()+"\n");

    }  

    public StringBuffer getResult(){

       return buffer;

    }  

}

再看看导出数据到XML文件的生成器实现,示例代码如下:

/**

 * 实现导出数据到XML文件的的生成器对象

 */

public class XmlBuilder implements Builder {

    /**

     * 用来记录构建的文件的内容,相当于产品

     */

    private StringBuffer buffer = new StringBuffer();

 

    public void buildBody(

Map<String, Collection<ExportDataModel>> mapData){

       buffer.append("  <Body>\n");

       for(String tblName : mapData.keySet()){

           //先拼接表名称

           buffer.append(

"    <Datas TableName=\""+tblName+"\">\n");

           //然后循环拼接具体数据

           for(ExportDataModel edm : mapData.get(tblName)){

              buffer.append("      <Data>\n");

              buffer.append("        <ProductId>"

+edm.getProductId()+"</ProductId>\n");

              buffer.append("        <Price>"+edm.getPrice()

+"</Price>\n");

              buffer.append("        <Amount>"+edm.getAmount()

+"</Amount>\n");

              buffer.append("      </Data>\n");

           }

           buffer.append("    </Datas>\n");

       }

       buffer.append("  </Body>\n");

    }

    public void buildFooter(ExportFooterModel efm) {

       buffer.append("  <Footer>\n");

       buffer.append("    <ExportUser>"+efm.getExportUser()

+"</ExportUser>\n");

       buffer.append("  </Footer>\n");

       buffer.append("</Report>\n");

    }

    public void buildHeader(ExportHeaderModel ehm) {

       buffer.append(

"<?xml version='1.0' encoding='gb2312'?>\n");

       buffer.append("<Report>\n");

       buffer.append("  <Header>\n");

       buffer.append("    <DepId>"+ehm.getDepId()+"</DepId>\n");

       buffer.append("    <ExportDate>"+ehm.getExportDate()

+"</ExportDate>\n");

       buffer.append("  </Header>\n");

    }

    public StringBuffer getResult(){

       return buffer;

    }

}

(4)指导者

有了具体的生成器实现后,需要有指导者来指导它进行具体的产品构建,由于构建的产品是文本内容,所以就不用单独定义产品对象了。示例代码如下:

/**

 * 指导者,指导使用生成器的接口来构建输出的文件的对象

 */

public class Director {

    /**

     * 持有当前需要使用的生成器对象

     */

    private Builder builder;

    /**

     * 构造方法,传入生成器对象

     * @param builder 生成器对象

     */

    public Director(Builder builder) {

       this.builder = builder;

    }

 

    /**

     * 指导生成器构建最终的输出的文件的对象

     * @param ehm 文件头的内容

     * @param mapData 数据的内容

     * @param efm 文件尾的内容

     */

    public void construct(ExportHeaderModel ehm,

Map<String,Collection<ExportDataModel>> mapData,

ExportFooterModel efm) {

       //1:先构建Header

       builder.buildHeader(ehm);

       //2:然后构建Body

       builder.buildBody(mapData);

       //3:然后构建Footer

       builder.buildFooter(efm);

    }

}

(5)都实现得差不多了,该来写个客户端好好测试一下了。示例代码如下:

public class Client {

    public static void main(String[] args) {

       //准备测试数据

       ExportHeaderModel ehm = new ExportHeaderModel();

       ehm.setDepId("一分公司");

       ehm.setExportDate("2010-05-18");

 

       Map<String,Collection<ExportDataModel>> mapData =

new HashMap<String,Collection<ExportDataModel>>();

       Collection<ExportDataModel> col =

new ArrayList<ExportDataModel>();

 

       ExportDataModel edm1 = new ExportDataModel();

       edm1.setProductId("产品001号");

       edm1.setPrice(100);

       edm1.setAmount(80);

 

       ExportDataModel edm2 = new ExportDataModel();

       edm2.setProductId("产品002号");

       edm2.setPrice(99);

       edm2.setAmount(55);     

       //把数据组装起来

       col.add(edm1);

       col.add(edm2);      

       mapData.put("销售记录表", col);

 

       ExportFooterModel efm = new ExportFooterModel();

       efm.setExportUser("张三");

 

       //测试输出到文本文件

       TxtBuilder txtBuilder = new TxtBuilder();

       //创建指导者对象

       Director director = new Director(txtBuilder);

       director.construct(ehm, mapData, efm);

       //把要输出的内容输出到控制台看看

       System.out.println("输出到文本文件的内容:\n"

+txtBuilder.getResult());

       //测试输出到xml文件

       XmlBuilder xmlBuilder = new XmlBuilder();

       Director director2 = new Director(xmlBuilder);

       director2.construct(ehm, mapData, efm);

       //把要输出的内容输出到控制台看看

       System.out.println("输出到XML文件的内容:\n"

+xmlBuilder.getResult());

    }

}

看了上面的示例会发现,其实生成器模式也挺简单的,好好理解一下。通过上面的讲述,应该能很清晰的看出生成器模式的实现方式和它的优势所在了,那就是对同一个构建过程,只要配置不同的生成器实现,就会生成出不同表现的对象。

 

原创内容,转载请注明出处【http://sishuok.com/forum/blogPost/list/5085.html

---------------------------------------------------------------------------

3
6
分享到:
评论

相关推荐

    研磨设计模式(完整带书签).part2.pdf

    第8章 生成器模式(Builder) 第9章 原型模式(Prototype) 第10章 中介者模式(Mediator) 第11章 代理模式(Proxy) 第12章 观察者模式(Observer) 第13章 命令模式(Command) 第14章 迭代器模式(Iterator) ...

    研磨设计模式(完整带书签).part1.pdf

    第8章 生成器模式(Builder) 第9章 原型模式(Prototype) 第10章 中介者模式(Mediator) 第11章 代理模式(Proxy) 第12章 观察者模式(Observer) 第13章 命令模式(Command) 第14章 迭代器模式(Iterator) ...

    研磨设计模式-part2

    第8章 生成器模式(Builder) 第9章 原型模式(Prototype) 第10章 中介者模式(Mediator) 第11章 代理模式(Proxy) 第12章 观察者模式(Observer) 第13章 命令模式(Command) 第14章 迭代器模式(Iterator) ...

    研磨设计模式.part2(共4个)

    第8章 生成器模式(Builder) 第9章 原型模式(Prototype) 第10章 中介者模式(Mediator) 第11章 代理模式(Proxy) 第12章 观察者模式(Observer) 第13章 命令模式(Command) 第14章 迭代器模式...

    研磨设计模式-part4

    第8章 生成器模式(Builder) 第9章 原型模式(Prototype) 第10章 中介者模式(Mediator) 第11章 代理模式(Proxy) 第12章 观察者模式(Observer) 第13章 命令模式(Command) 第14章 迭代器模式(Iterator) ...

    研磨设计模式-part3

    第8章 生成器模式(Builder) 第9章 原型模式(Prototype) 第10章 中介者模式(Mediator) 第11章 代理模式(Proxy) 第12章 观察者模式(Observer) 第13章 命令模式(Command) 第14章 迭代器模式(Iterator) ...

    研磨设计模式.part3(共4个)

    第8章 生成器模式(Builder) 第9章 原型模式(Prototype) 第10章 中介者模式(Mediator) 第11章 代理模式(Proxy) 第12章 观察者模式(Observer) 第13章 命令模式(Command) 第14章 迭代器模式...

    研磨设计模式.part4(共4个)

    第8章 生成器模式(Builder) 第9章 原型模式(Prototype) 第10章 中介者模式(Mediator) 第11章 代理模式(Proxy) 第12章 观察者模式(Observer) 第13章 命令模式(Command) 第14章 迭代器模式...

    研磨设计模式.part1(共4个)

    第8章 生成器模式(Builder) 第9章 原型模式(Prototype) 第10章 中介者模式(Mediator) 第11章 代理模式(Proxy) 第12章 观察者模式(Observer) 第13章 命令模式(Command) 第14章 迭代器模式...

    DesignPattern

    《研磨设计模式》书中的例子 --第二章:简单工厂 本质:选择实现 --第三章:外观模式(Facade) 本质:封装交互,简化调用 --第四章:适配器模式(Adapter) 本质:转换匹配,复用功能 --第五章:单例模式(Singleton) ...

Global site tag (gtag.js) - Google Analytics