8.1 场景问题
8.1.1 继续导出数据的应用框架
在讨论工厂方法模式的时候,提到了一个导出数据的应用框架。
对于导出数据的应用框架,通常在导出数据上,会有一些约定的方式,比如导出成:文本格式、数据库备份形式、Excel格式、Xml格式等等。
在工厂方法模式章节里面,讨论并使用工厂方法模式来解决了如何选择具体导出方式的问题,并没有涉及到每种方式具体如何实现。
换句话说,在讨论工厂方法模式的时候,并没有讨论如何实现导出成文本、Xml等具体的格式,本章就来讨论这个问题。
对于导出数据的应用框架,通常对于具体的导出内容和格式是有要求的,假如现在有如下的要求,简单描述一下:
- 导出的文件,不管什么格式,都分成三个部分,分别是文件头、文件体和文件尾
- 在文件头部分,需要描述如下信息:分公司或门市点编号、导出数据的日期,对于文本格式,中间用逗号分隔
- 在文件体部分,需要描述如下信息:表名称、然后分条描述数据。对于文本格式,表名称单独占一行,数据描述一行算一条数据,字段间用逗号分隔。
- 在文件尾部分,需要描述如下信息:输出人
现在就要来实现上述功能。为了演示简单点,在工厂方法模式里面已经实现的功能,这里就不去重复了,这里只关心如何实现导出文件,而且只实现导出成文本格式和XML格式就可以了,其它的就不去考虑了。
8.1.2 不用模式的解决方案
不就是要实现导出数据到文本文件和XML文件吗,其实不管什么格式,需要导出的数据是一样的,只是具体导出到文件中的内容,会随着格式的不同而不同。
(1)先来把描述文件各个部分的数据对象定义出来,先看描述输出到文件头的内容的对象,示例代码如下:
/** * 描述输出到文件头的内容的对象 */ 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; } } |
接下来看看描述输出数据的对象,示例代码如下:
/** * 描述输出数据的对象 */ 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; } } |
接下来看看描述输出到文件尾的内容的对象,示例代码如下:
/** * 描述输出到文件尾的内容的对象 */ public class ExportFooterModel { /** * 输出人 */ private String exportUser; public String getExportUser() { return exportUser; } public void setExportUser(String exportUser) { this.exportUser = exportUser; } } |
(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); } } |
(3)接下来看看导出数据到XML文件的对象,比较麻烦,要按照XML的格式进行拼接,示例代码如下:
/** * 导出数据到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); } } |
(4)看看客户端,如何来使用这些对象,示例代码如下:
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> |
8.1.3 有何问题
仔细观察上面的实现,会发现,不管是输出成文本文件,还是输出到XML文件,在实现的时候,步骤基本上都是一样的,都大致分成了如下四步:
- 先拼接文件头的内容
- 然后拼接文件体的内容
- 再拼接文件尾的内容
- 最后把拼接好的内容输出出去成为文件
也就是说,对于不同的输出格式,处理步骤是一样的,但是具体每步的实现是不一样的。按照现在的实现方式,就存在如下的问题:
(1)构建每种输出格式的文件内容的时候,都会重复这几个处理步骤,应该提炼出来,形成公共的处理过程
(2)今后可能会有很多不同输出格式的要求,这就需要在处理过程不变的情况下,能方便的切换不同的输出格式的处理
换句话来说,也就是构建每种格式的数据文件的处理过程,应该和具体的步骤实现分开,这样就能够复用处理过程,而且能很容易的切换不同的输出格式。
可是该如何实现呢?
相关推荐
Builder模式模式介绍模式的定义将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。Android源码中的模式实现在Android源码
Builder模式 设计模式 Builder模式
Builder模式 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 统设计中,有时候面临着一个“复杂系统”的创建工作,该对象通常由各个部分的子对象用一定的算法构成,或者说按一定的...
23种设计模式之四(创建型模式)Builder模式
介绍UserBuilder builder = new UserBuilder();User user = builder.builder();可以通过上述代码
在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成。那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Builder模式来替代多参数...
【Java面试题】builder模式
一个builder 设计 模式 的源码,
BUILDER模式 C++实现
demo中使用了设计模式中的建造者模式,代码非常精简,本地可正常运行,亲测有效!
NULL 博文链接:https://wy649898543.iteye.com/blog/1431751
将一个复杂对象的构造与它的表示分离,使同样的构建 过程可以创建不同的表示,这样的设计模式被称为建造者模式。
builder设计模式
在这里与各位分享本人从网络上下载的C#面向对象设计模式纵横谈系列视频,共有25节,除了第一节需要各位贡献一点资源分以作为对本人上传资源的回馈,后面的其他资源均不需要... 这是第4节:创建型模式Builder生成器模式
Builder模式Demo
C#设计模式之建造者(Builder)模式示例源代码
东北大学设计模式实验 实现单例模式,组合模式,Builder模式,装饰器模式,并使用设计模式实现赌场
用于学习android java builder模式
FreeBuilder 为 Java 1.6 自动生成 Builder 模式。 当设计类的构造函数或静态工厂具有多个参数时,Builder 模式是一个不错的选择。