生成器模式(Builder)

来源:互联网 发布:数据库原理pdf百度云 编辑:程序博客网 时间:2024/06/05 09:44
@@@模式定义:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。


@@@练习示例: 
继续工厂方法模式中的导出数据的应用框架。


@@@示例代码:
\export\ExportHeaderModel.java

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;/** * 描述输出到文件头的内容的类 */public class ExportHeaderModel {    /**     * 分公司或门市点编号     */private String depId;/** * 导出数据的日期 */private String exportDate;public String getDepId() {return depId;}public void setDepId(String depId) {this.depId = depId;}public String getExportDate() {return exportDate;}public void setExportDate(String exportDate) {this.exportDate = exportDate;}}

\export\ExportDataModel.java

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;/** * 描述输出数据的类 */public class ExportDataModel {    /**     * 产品编号     */private String productId;/** * 销售价格 */private double price;/** * 销售数量 */private double amount;public String getProductId() {return productId;}public void setProductId(String productId) {this.productId = productId;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}public double getAmount() {return amount;}public void setAmount(double amount) {this.amount = amount;}}

\export\ExportFooterModel.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;/** * 描述输出到文件尾的内容的类 */public class ExportFooterModel {    /**     * 输出人     */private String exportUser;public String getExportUser() {return exportUser;}public void setExportUser(String exportUser) {this.exportUser = exportUser;}}

\export\ExportToTxt.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;import java.util.Collection;import java.util.Map;/** * 导出数据到文本文件的类 */public class ExportToTxt {    /**     * 导出数据到文本文件     * @param ehm 文件头的内容     * @param mapData 数据的内容     * @param efm 文件尾的内容     */public void export(ExportHeaderModel ehm,           Map<String, Collection<ExportDataModel>> mapData,           ExportFooterModel efm) {// 用来记录最终输出的文件内容StringBuffer buffer = new StringBuffer();// 1: 先来拼接文件头的内容    buffer.append(ehm.getDepId() + ", " + ehm.getExportDate() + "\n");    // 2: 接着来拼接文件体的内容    for (String tblName : mapData.keySet()) {    // 先拼接表名称    buffer.append(tblName + "\n");    // 然后循环拼接具体数据    for (ExportDataModel edm : mapData.get(tblName)) {    buffer.append(edm.getProductId() + ", " +     edm.getPrice() + ", " + edm.getAmount() + "\n");    }    }    // 3: 最后来拼接文件尾的内容    buffer.append(efm.getExportUser());        // 为了演示的简洁性,省略写输出文件的代码    // 把要输出的内容输出到控制台看看    System.out.println("输出到文本文件的内容: \n" + buffer);}}

\export\ExportToXml.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;import java.util.Collection;import java.util.Map;/** * 导出数据到XML文件的类 */public class ExportToXml {/**     * 导出数据到XML文件     * @param ehm 文件头的内容     * @param mapData 数据的内容     * @param efm 文件尾的内容     */public void export(ExportHeaderModel ehm,           Map<String, Collection<ExportDataModel>> mapData,           ExportFooterModel efm) {// 用来记录最终输出的文件内容StringBuffer buffer = new StringBuffer();// 1: 先来拼接文件头的内容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");    // 2: 接着来拼接文件体的内容    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");    // 3: 最后来拼接文件尾的内容    buffer.append("  <Footer>\n");    buffer.append("    <ExportUser>" + efm.getExportUser() + "</ExportUser>\n");    buffer.append("  </Footer>\n");    buffer.append("</Report>\n");        // 为了演示的简洁性,省略写输出文件的代码    // 把要输出的内容输出到控制台看看    System.out.println("输出到XML文件的内容: \n" + buffer);}}

\user\Client.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package user;import java.util.ArrayList;import java.util.Collection;import java.util.HashMap;import java.util.Map;import export.ExportDataModel;import export.ExportFooterModel;import export.ExportHeaderModel;import export.ExportToTxt;import export.ExportToXml;public class Client {    public static void main(String[] args) {    // 准备测试数据    ExportHeaderModel ehm = new ExportHeaderModel();    ehm.setDepId("一分公司");    ehm.setExportDate("2013-06-02");        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(108);        edm2.setAmount(56);                // 把数据组装起来        col.add(edm1);        col.add(edm2);        mapData.put("销售记录表", col);                ExportFooterModel efm = new ExportFooterModel();        efm.setExportUser("李小二");                // 测试输出到文本文件        ExportToTxt toTxt = new ExportToTxt();        toTxt.export(ehm, mapData, efm);                // 测试输出到xml文件        ExportToXml toXml = new ExportToXml();        toXml.export(ehm, mapData, efm);    }}

-------------------------------------------------------------
不使用模式时存在的问题 : 
对于不同的输出格式,处理步骤是一样的,但是每步的具体实现是不一样的。
构建每种输出格式的文件内容时,都会重复这几个处理步骤,应该提炼出来,形成公共的处理过程。
今后可能会有很多不同输出格式的要求,这就需要在处理过程不变的情况下,能方便地切换不同的输出格式的处理。
构建每种格式的数据文件的处理过程,应该和具体的步骤实现分开,
这样就能够复用处理过程,而且能很容易地切换不同的输出格式。
-------------------------------------------------------------


\export\Builder.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;import java.util.Collection;import java.util.Map;/** * 生成器接口,定义创建一个输出文件对象所需的各个部件的操作 */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);}

\export\TxtBuilder.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;import java.util.Collection;import java.util.Map;/** * 实现导出数据到文本文件的具体生成器类 */public class TxtBuilder implements Builder {/** * 用来记录构建的文件的内容,相当于产品 */private StringBuffer buffer = new StringBuffer();@Overridepublic void buildHeader(ExportHeaderModel ehm) { buffer.append(ehm.getDepId() + ", " + ehm.getExportDate() + "\n");}@Overridepublic 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");        }        }}@Overridepublic void buildFooter(ExportFooterModel efm) {buffer.append(efm.getExportUser());}public StringBuffer getResult() {return buffer;}}

\export\XmlBuilder.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;import java.util.Collection;import java.util.Map;/** * 实现导出数据到XML文件的具体生成器类 */public class XmlBuilder implements Builder {/** * 用来记录构建的文件的内容,相当于产品 */private StringBuffer buffer = new StringBuffer();@Overridepublic 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");}@Overridepublic 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");}@Overridepublic void buildFooter(ExportFooterModel efm) {buffer.append("  <Footer>\n");    buffer.append("    <ExportUser>" + efm.getExportUser() + "</ExportUser>\n");    buffer.append("  </Footer>\n");    buffer.append("</Report>\n");}public StringBuffer getResult() {return buffer;}}

\export\Director.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;import java.util.Collection;import java.util.Map;/** * 指导者,指导使用生成器的接口来构建输出的文件的对象 */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);}}

\user\Client2.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package user;import java.util.ArrayList;import java.util.Collection;import java.util.HashMap;import java.util.Map;import export.Director;import export.ExportDataModel;import export.ExportFooterModel;import export.ExportHeaderModel;import export.TxtBuilder;import export.XmlBuilder;public class Client2 {    public static void main(String[] args) {    // 准备测试数据    ExportHeaderModel ehm = new ExportHeaderModel();    ehm.setDepId("一分公司");    ehm.setExportDate("2013-06-02");        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(108);        edm2.setAmount(56);                // 把数据组装起来        col.add(edm1);        col.add(edm2);        mapData.put("销售记录表", col);                ExportFooterModel efm = new ExportFooterModel();        efm.setExportUser("李小二");                // 测试输出到文本文件        TxtBuilder txtBuilder = new TxtBuilder();        // 创建指导者对象        Director txtDirector = new Director(txtBuilder);        txtDirector.construct(ehm, mapData, efm);        // 把要输出的内容输出到控制台看看        System.out.println("输出到文本文件的内容: \n" +        txtBuilder.getResult());                // 测试输出到xml文件        XmlBuilder xmlBuilder = new XmlBuilder();        // 创建指导者对象        Director xmlDirector = new Director(xmlBuilder);        xmlDirector.construct(ehm, mapData, efm);        // 把要输出的内容输出到控制台看看        System.out.println("输出到XML文件的内容: \n" +        xmlBuilder.getResult());            }}

@@@模式的实现:
1. 生成器中的每个方法可以有两部分的功能,一部分是创建部件对象,另一部分是组装部件。
2. 指导者承担的是整体构建算法部分,是相对不变的。
3. 产品构建过程中,指导者和生成器之间可能会存在比较复杂的交互过程。
4. 客户端最终从Builder实现里面获取最终装配好的产品。
5. 一般不需要对产品定义抽象接口,因为最终构建出来的产品千差万别。


@@@模式的功能:
生成器模式的主要功能是构建复杂的产品,而且是细化的、分步骤地构建产品,
也就是生成器模式重在一步一步解决构造复杂对象的问题。
更重要的是,这个构建的过程是统一的、固定不变的,变化的部分放到生成器部分了,只要配置不同的生成器,
那么同样的构建过程,就能构建出不同的产品来。


@@@模式的构成:
1. Builder接口,定义了如何构建各个部件,如何装配产品。
2. Director,定义了使用部件装配产品的步骤。


@@@模式的优点:
1. 松散耦合。
2. 可以很容易地改变产品的内部表示。
3. 更好的复用性


@@@模式的缺点:



@@@模式的本质:
分离整体构建算法和部件构造过程。


@@@模式体现的设计原则:

原创粉丝点击