设计模式讲解 — 生成器模式(1)

场景问题

导出数据的应用框架

对于导出数据的应用框架,通常在导出数据上,会有一些约定的方式,比如导出成:文本格式、数据库备份形式、Excel格式、Xml格式等等。

对于每种方式具体如何实现,通常对于具体的导出内容和格式是有要求的,假如现在有如下的要求,简单描述一下:

  • 导出的文件,不管什么格式,都分成三个部分,分别是文件头、文件体和文件尾
  • 在文件头部分,需要描述如下信息:分公司或门市点编号、导出数据的日期,对于文本格式,中间用逗号分隔
  • 在文件体部分,需要描述如下信息:表名称、然后分条描述数据。对于文本格式,表名称单独占一行,数据描述一行算一条数据,字段间用逗号分隔。
  • 在文件尾部分,需要描述如下信息:输出人

现在就要来实现上述功能。为了演示简单点,这里只关心如何实现导出文件,而且只实现导出成文本格式和XML格式就可以了,其它的就不去考虑了。

不用模式的解决方案

不就是要实现导出数据到文本文件和XML文件吗,其实不管什么格式,需要导出的数据是一样的,只是具体导出到文件中的内容,会随着格式的不同而不同。

源码地址:https://gitee.com/liupeifeng3514/design_pattern

(1)先来把描述文件各个部分的数据对象定义出来,示例代码如下:

/**
 * 描述输出到文件头的内容的对象
 */
public class ExportHeaderModel {
    /**
     * 分公司或门市点编号
     */
    private String depId;
    /**
     * 导出数据的日期
     */
    private String exportDate;

    // set、get方法
}
/**
 * 描述输出数据的对象
 */
public class ExportDataModel {
    /**
     * 产品编号
     */
    private String productId;
    /**
     * 销售价格
     */
    private double price;
    /**
     * 销售数量
     */
    private double amount;

    // set、get方法
}
/**
 * 描述输出到文件尾的内容的对象
 */
public class ExportFooterModel {
    /**
     * 输出人
     */
    private String exportUser;

    // set、get方法
}

(2)接下来具体的看看导出的实现,示例代码如下:

/**
 * 导出数据到文本文件的对象
 */
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);
    }
}
/**
 * 导出数据到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);
    }
}

(3)看看客户端,如何来使用这些对象,示例代码如下:

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("张三");

        // 测试输出到文本文件
        ExportToTxt toTxt = new ExportToTxt();
        toTxt.export(ehm, mapData, efm);
        // 测试输出到xml文件
        ExportToXml toXml = new ExportToXml();
        toXml.export(ehm, mapData, efm);
    }
}

运行结果如下:

输出到文本文件的内容:
一分公司,2010-05-18
销售记录表
产品001号,100.0,80.0
产品002号,99.0,55.0
张三
输出到XML文件的内容:
<?xml version='1.0' encoding='gb2312'?>
<Report>
  <Header>
    <DepId>一分公司</DepId>
    <ExportDate>2010-05-18</ExportDate>
  </Header>
  <Body>
    <Datas TableName="销售记录表">
      <Data>
        <ProductId>产品001号</ProductId>
        <Price>100.0</Price>
        <Amount>80.0</Amount>
      </Data>
      <Data>
        <ProductId>产品002号</ProductId>
        <Price>99.0</Price>
        <Amount>55.0</Amount>
      </Data>
    </Datas>
  </Body>
  <Footer>
    <ExportUser>张三</ExportUser>
  </Footer>
</Report>
有何问题

仔细观察上面的实现,会发现,不管是输出成文本文件,还是输出到XML文件,在实现的时候,步骤基本上都是一样的,都大致分成了如下四步:

  1. 先拼接文件头的内容
  2. 然后拼接文件体的内容
  3. 再拼接文件尾的内容
  4. 最后把拼接好的内容输出出去成为文件

也就是说,对于不同的输出格式,处理步骤是一样的,但是具体每步的实现是不一样的。按照现在的实现方式,就存在如下的问题:

  1. 构建每种输出格式的文件内容的时候,都会重复这几个处理步骤,应该提炼出来,形成公共的处理过程
  2. 今后可能会有很多不同输出格式的要求,这就需要在处理过程不变的情况下,能方便的切换不同的输出格式的处理

换句话来说,也就是构建每种格式的数据文件的处理过程,应该和具体的步骤实现分开,这样就能够复用处理过程,而且能很容易的切换不同的输出格式

可是该如何实现呢?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值