首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件开发 >

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

2012-11-17 
研磨设计模式 之 生成器模式(Builder)2 ——跟着cc学设计系列8.2? 解决方案8.2.1? 生成器模式来解决用来解决

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

8.2? 解决方案8.2.1? 生成器模式来解决

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

(1)生成器模式定义

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

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

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

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

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

8.2.2? 模式结构和说明

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

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

图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所示:

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

图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】

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

热点排行