`

生成器模式builder

阅读更多
问题引人:继续导出数据的应用框架
讨论工厂方法模式时,提到了一个导出数据的应用框架。比如导出成文本格式,数据库备份形式,excel格式,xml格式等。
在工厂模式中,并没有讨论如何实现导出成文本、xml文件等,假如需求有以下:
1,导出的文件,不管什么格式,分为3部分,文件头,文件体和文件尾
2,在文件头,需要描述:分公司或门市点编号。导出数据的日期,对于文本格式,中间用逗号分隔。
3,文件体中,需要描述:表名称,然后分条描述数据。对于文本格式,表名称单独占一行,数据描述一行算一条数据,字段间用逗号分隔,
4,文件尾,需要描述:输出人
为简便起见,只实现导出成文本格式和Xml格式
要先将文件各个部分的数据对象定义出来。
package notusingMode;

//导出文件头模型对象
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;
	}

}

package notusingMode;
//描述导出数据的对象???? 即对应导出的文件体部分
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;
	}

}


package notusingMode;
//描述输出到文件尾的内容的对象
public class ExportFooterModel {

	private String exportUser;

	public String getExportUser() {
		return exportUser;
	}
	public void setExportUser(String exportUser) {
		this.exportUser = exportUser;
	}
	
}


package notusingMode;
//具体导出对象,导出到文件文件的对象
import java.util.Map;
import java.util.Collection;
public class ExportToTxt {
//	Map<String,Collection<ExportDataModel>>存储数据体,String类型的key代表表名称,后面的集合代表表格中的记录
	public void export(ExportHeaderModel header,Map<String,Collection<ExportDataModel>> body,ExportFooterModel footer){
		//用来记录最终输出的文件内容
		StringBuffer buffer = new StringBuffer();
		
		//1:先拼出文件头
		buffer.append(header.getDepId()+","+header.getExportDate()+"\n");
		//2:文件体
		for(String tableName:body.keySet()){
			//先拼接表格名称
			buffer.append(tableName+"\n");
//			循环拼接具体数据
			for(ExportDataModel data:body.get(tableName)){
				buffer.append(data.getProductId()+","+data.getPrice()+","+data.getAmount()+"\n");
			}
			
		}
		
		//3:文件尾
		buffer.append(footer.getExportUser()+"\n");
		
		//为了简单,不写出输出文件的代码了,将要输出的内容输出到控制台看看
		System.out.println("输出到文本文件的内容是:\n"+buffer);
		
	}
}

package notusingMode;

import java.util.Collection;
import java.util.Map;

public class ExportToXml {
// Map<String,Collection<ExportDataModel>>存储数据体,String类型的key代表表名称,后面的集合代表表格中的记录
public void export(ExportHeaderModel header,Map<String,Collection<ExportDataModel>> body,ExportFooterModel footer){

//用来记录最终输出的文件内容
StringBuffer buffer = new StringBuffer();

//1:先拼出文件头
buffer.append("<?xml version='1.0' encoding = 'gb2312' ?>\n");
buffer.append("<Report>\n");
buffer.append("  <Header>\n");
buffer.append("    <DeptId>"+header.getDepId()+"</DeptId>\n");
buffer.append("    <ExportDate>"+header.getExportDate()+"</ExportDate>\n");
buffer.append("  </Header>\n");

//2:文件体

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

for(String tableName:body.keySet()){
//先拼接表格名称
buffer.append("    <Datas TableName=\""+tableName+"\">\n");

// 循环拼接具体数据
for(ExportDataModel data:body.get(tableName)){
buffer.append("      <Data>\n");
buffer.append("        <ProductID>"+data.getProductId()+"</ProductID>\n");
buffer.append("        <Price>"+data.getPrice()+"</Price>\n");
buffer.append("        <Amount>"+data.getAmount()+"</Amount>\n");
buffer.append("      </Data>\n");
}
buffer.append("    </Datas>\n");

}

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

//文件尾
buffer.append("  <Footer>\n");
buffer.append("    <ExportUser>"+footer.getExportUser()+"</ExportUser>\n");

buffer.append("  </Footer>\n");
buffer.append("</Report>\n");
System.out.println("输出到XML文件的内容是:\n"+buffer);


}
}



上述实例notusingMode包中是没有使用模式的解决方案,观察程序可看出,无论导出为xml还是txt,步骤基本一样的,先拼接头,体,尾,最后将拼接完的
内容输出成为文件。也就是不同的输出格式,处理步骤是一样的,但是每一步的具体实现是不一样的,存在的问题如下:
(1)构建每种输出格式的文件内容时,都会重复这几个步骤,应该提炼出来,形成公共的处理过程。
(2)今后可能会有很多不同输出格式的要求,这就需要在处理过程不变的情况下,能方便地切换到不同的输出格式的处理。
构造每种格式的数据文件的处理过程,应该和具体的步骤实现分开,这样就能够复用处理过程,
而且能很容易切换到不同地输出格式。如何实现呢-----》生成器模式
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以产生不同的表示。
思路:先把构建过程独立出来,在生成器模式中称为指导者,由他来指导装配过程,但是不负责每个步骤的具体实现,必须要有能具体实现每部的对象,
在生成器模式中,将这些对象称为生成器。这样,指导者就是可以重用的构建过程,但生成器就是可以被切换的具体实现。前面的每种具体的导出文件格式的实现
就相当于生成器。
生成器模式的结构:
(1)Builder:生成器接口,定义创建一个Product对象所需的各个部件的操作。
(2)ConcreteBuilder:具体的生成器实现,实现各个部件的创建,并负责组装Product对象的各个部件,同时日工一个让用户获取组装完成后的产品对象的方法
(3)Director:指导者,主要用来使用Builder接口,以一个统一的过程来创建所需的Product对象
(4)Product:产品,表示被生成器构建的复杂对象,包含多个部件
两个重要部分:Builder接口,定义了如何构建各个部件,Director,是知道如何组合来构建产品,也就是说它负责整体的构建算法,通常是分步骤来执行。
生成器模式都存在两个部分,一个部分是部件构建和产品装配,另一个是整体构建的算法。它强调的是固定整体构建的算法,而灵活地扩展和切换部件的具体构造
生成器模式结构的实现代码:
package builder;
//生成器接口
public interface Builder {
//示意方法,构建某个部件,如果构建多个部件,就有多个方法
	public void buildPart();
}

package builder;
//具体生成器,负责实现各个部件的创建,并组装起来,提供给用户
public class ConcreteBuilder implements Builder {

	private Product resultProduct;
	
	@Override
	public void buildPart() {
   //构建某个部件的功能处理
	}

	public Product getProduct(){
//		获取生成器最终构建的产品对象,返回给用户
		return resultProduct;
	}
}

package builder;
//产品对象接口
public interface Product {

}

package builder;
//指导者,使用Builder接口来构建产品的对象
public class Director {

	private Builder builder;
	
	
	public Director(Builder builder) {  //传入生成器对象
		this.builder = builder;
	}
	public void construct(){
		builder.buildPart();  //
	}
}

使用生成器模式解决上述实际问题:
其中的模型部分(包括数据,头,尾)不用改变,需要增加的就是生成器对象等。
package builderSolve;

import java.util.Collection;
import java.util.Map;

public interface Builder {

	public void buildHeader(ExportHeaderModel header);
	public void buildFooter(ExportFooterModel footer);
	public void buildBody(Map<String, Collection<ExportDataModel>> body);
}

package builderSolve;

import java.util.Collection;
import java.util.Map;

public class TxtBuilder implements Builder {

	private StringBuffer buffer = new StringBuffer();

	public StringBuffer getResult(){
		//返回构造完的复杂对象
		return buffer;
	}

	@Override
	public void buildBody(Map<String,Collection<ExportDataModel>> body) {
		for(String tableName:body.keySet()){
			//先拼接表格名称
			buffer.append(tableName+"\n");
//			循环拼接具体数据
			for(ExportDataModel data:body.get(tableName)){
				buffer.append(data.getProductId()+","+data.getPrice()+","+data.getAmount()+"\n");
			}
			
		}
	}

	@Override
	public void buildFooter(ExportFooterModel footer) {
		buffer.append(footer.getExportUser()+"\n");
	}

	@Override
	public void buildHeader(ExportHeaderModel header) {
		buffer.append(header.getDepId()+","+header.getExportDate()+"\n");
	}
}

package builderSolve;

import java.util.Collection;
import java.util.Map;

public class XmlBuilder implements Builder {

	private StringBuffer buffer = new StringBuffer();

	public StringBuffer getResult() {
		// 返回构造完的复杂对象
		return buffer;
	}

	@Override
	public void buildBody(Map<String, Collection<ExportDataModel>> body) {
		buffer.append("  <Body>\n");

		for (String tableName : body.keySet()) {
			// 先拼接表格名称
			buffer.append("    <Datas TableName=\"" + tableName + "\">\n");

			// 循环拼接具体数据
			for (ExportDataModel data : body.get(tableName)) {
				buffer.append("      <Data>\n");
				buffer.append("        <ProductID>" + data.getProductId()
						+ "</ProductID>\n");
				buffer.append("        <Price>" + data.getPrice()
						+ "</Price>\n");
				buffer.append("        <Amount>" + data.getAmount()
						+ "</Amount>\n");
				buffer.append("      </Data>\n");
			}
			buffer.append("    </Datas>\n");

		}

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

	@Override
	public void buildFooter(ExportFooterModel footer) {
		//文件尾
		buffer.append("  <Footer>\n");
		buffer.append("    <ExportUser>"+footer.getExportUser()+"</ExportUser>\n");
		
		buffer.append("  </Footer>\n");
		buffer.append("</Report>\n");
	}

	@Override
	public void buildHeader(ExportHeaderModel header) {
		buffer.append("<?xml version='1.0' encoding = 'gb2312' ?>\n");
		buffer.append("<Report>\n");
		buffer.append("  <Header>\n");
		buffer.append("    <DeptId>" + header.getDepId() + "</DeptId>\n");
		buffer.append("    <ExportDate>" + header.getExportDate()
				+ "</ExportDate>\n");
		buffer.append("  </Header>\n");
	}

}


package builderSolve;

import java.util.Collection;
import java.util.Map;

//指导者,使用Builder接口来构建产品的对象
public class Director {

	private Builder builder;
	
	
	public Director(Builder builder) {  //传入生成器对象
		this.builder = builder;
	}


	public void construct(ExportHeaderModel header,Map<String,Collection<ExportDataModel>> body,ExportFooterModel footer){
		builder.buildHeader(header);
		builder.buildBody(body);
		builder.buildFooter(footer);
	}
}


package builderSolve;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

public class Client {
	public static void main(String[] args) {

		//准备测试数据
		ExportHeaderModel header = new ExportHeaderModel();
		header.setDepId("一分公司");
		header.setExportDate("2011-03-25");
		
		Map<String,Collection<ExportDataModel>> map = new HashMap<String,Collection<ExportDataModel>>();
		Collection<ExportDataModel> collection = new ArrayList<ExportDataModel>();
		ExportDataModel data1 = new ExportDataModel();
		data1.setAmount(43);
		data1.setPrice(56.4);
		data1.setProductId("产品001号");
		
		ExportDataModel data2 = new ExportDataModel();
		data2.setAmount(444);
		data2.setPrice(26.4);
		data2.setProductId("产品002号");
		
		collection.add(data2);
		collection.add(data1);
		map.put("销售记录表", collection);
		
		ExportFooterModel footer = new ExportFooterModel();
		footer.setExportUser("张三");
		
		
			// 测试输出到文本文件
		TxtBuilder txtBuilder = new TxtBuilder();
		Director director = new Director(txtBuilder);
		director.construct(header, map, footer);
		System.out.println("输出到txt文件的内容是:\n"+txtBuilder.getResult());
		
		//测试输出到xml文件
		
		XmlBuilder xmlBuilder = new XmlBuilder();
		Director director2 = new Director(xmlBuilder);
		director2.construct(header, map, footer);
		System.out.println("输出到XML文件的内容是:\n"+xmlBuilder.getResult());

	}
}


使用生成器模式构建复杂对象
实际应用,要创建一个保险合同的对象,里面有很多属性的值都有越是,比如合同可和个人签或是公司签,但不能同时和个人和公司签。如何创建呢?
由于用Builder模式创建某个对象,因此没有必要再定义一个Builder接口,直接提供一个具体的构建器类就可以了。还可以将指导者和客户端的功能合并起来。
例子:使用builder模式,先不考虑带约束,noRestrictContract包内.

使用builder模式,考虑带约束,restrictContract包内.

通常两个地方可以添加约束规则。(1)是构建器的每一个类似于setter的方法,可以在这里进行单个数据的约束规则校验,如果不正确,就抛出IllegalStateException
(2)构建器的build方法,在创建保险合同对象之前,对所有的数据都可以进行数据的约束规则校验,尤其是那些涉及到几个数据之间的约束关系,在这里校验会比较合适,如果不正确,就抛出IllegalStateException

更进一步,把构建器对象和被构建的对象合并
使用内联类,将构建器对象合并到被构建的对象里面去,如innerClassContract包中示例

builder模式的本质:分离整体构建算法和部件的构建


















分享到:
评论

相关推荐

    C#面向对象设计模式4:生成器(Builder)

    生成器模式通常由四个主要角色组成:Director(导演)、Concrete Builder(具体生成器)、Product(产品)和Builder(生成器接口)。 在C#中,我们可以定义一个生成器接口,包含创建产品各个部分的方法,如`...

    C#设计模式之Builder生成器模式解决带老婆配置电脑问题实例

    本文主要介绍了C#设计模式之Builder生成器模式解决带老婆配置电脑问题,简单介绍了生成器模式的概念、功能并结合具体实例形式分析了C#生成器模式解决配电脑问题的步骤与相关操作技巧。 一、 Builder生成器模式定义 ...

    生成器模式代码示例

    生成器模式是一种设计模式,属于创建型模式,它允许我们分步骤构建复杂对象,而无需提前知道整个对象的完整结构。这种模式的核心在于延迟初始化,它使得我们可以根据需要逐步构建对象,而不是一次性创建所有部分。在...

    23钟设计模式之生成器模式

    生成器模式(Builder Pattern)是一种创造型设计模式,它将一个复杂对象的构建与它的表示分离,使得同样的构建可以创建不同的表示。这种模式可以在以下情况下使用: 1. 当创建复杂对象的算法应该独立于该对象的组成...

    java生成器模式

    生成器模式(Builder Pattern)是Java设计模式中的创建型模式之一,主要解决复杂对象的构建问题,通过将构造过程逐步分解,使得构造过程与表示分离,使得同样的构建过程可以创建不同的表示。这种模式通常用于创建...

    C#面向对象设计模式纵横谈\4 创建型模式Builder生成器模式.zip

    在这里与各位分享本人从网络上下载的C#面向对象设计模式纵横谈系列视频,共有25节,除了第一节需要各位贡献一点资源分以作为对本人上传资源的回馈,后面的其他资源均不需要... 这是第4节:创建型模式Builder生成器模式

    C#面向对象设计模式纵横谈(4):Builder 生成器模式(创建型模式)

    在C#中,Builder模式常常应用于游戏对象生成、配置文件解析、数据库记录映射等领域。例如,游戏中的角色创建,可能需要设置角色的属性、技能等,这些可以通过不同的Builder来实现;而在数据库操作中,ORM框架如...

    【设计模式】- 生成器模式(Builder)(csdn)————程序.pdf

    生成器模式,也称为建造者模式,是一种设计模式,用于创建复杂对象,它允许你按照一系列步骤来构造对象,而这些步骤可以通过不同的实现来产生不同形式的对象。生成器模式的核心在于分离了对象的构造过程和表示细节,...

    生成器模式源代码

    生成器模式,也被称为构建器模式,是一种软件设计模式,主要用在对象的创建过程中,它将复杂的构建过程分解为一系列简单的步骤,使得构建过程可配置,并且可以独立于对象的表示进行。在C#中,生成器模式的实现通常...

    iOS 生成器模式demo

    在iOS开发中,生成器模式(Builder Pattern)是一种设计模式,它允许我们分步骤构建复杂的对象,而无需暴露创建过程的复杂性。这种模式在处理需要多种构建方式或需要逐步构造对象的情况时特别有用。标题“iOS 生成器...

    生成器模式

    生成器模式是一种设计模式,属于创建型模式,它在软件工程中被广泛应用于解决大量对象的创建问题。这种模式的主要思想是将对象的创建过程分解为一系列步骤,使得客户端可以根据需要选择执行这些步骤,从而实现延迟...

    Builder(生成器)模式[文].pdf

    Builder模式是一种设计模式,主要目的是将复杂对象的构建与其表示分离,使得构建过程可以独立于表示进行。在Builder模式中,我们通常会定义一个抽象Builder类,它规定了如何创建复杂对象的各个部分,然后创建具体...

    生成器模式例子

    在《Head First Design Patterns》文中是这么介绍生成器模式的,“封装一个产品的构造过程,并允许按步骤构造”,感觉说得不是很清楚。而在网上查找相关资料是这么解释的,建造者模式(Builder Pattern)使用多个简单...

    iOS 生成器模式

    生成器模式是设计模式中的一种,它属于创建型模式,主要用来处理复杂对象的构建过程。在这个“iOS生成器模式”中,我们将深入探讨如何在iOS开发中应用这个模式。 生成器模式的核心思想是将对象的创建过程和对象本身...

    Builder(生成器)模式参照.pdf

    Builder 模式(生成器模式) Builder 模式是一种创建型设计模式,它将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示。GoF 将其定义为将一个复杂对象的构建与它的表示分离,使得同样的...

    Builder(生成器)模式借鉴.pdf

    Builder 模式(生成器模式) Builder 模式是一种创建型设计模式,它将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。Builder 模式与 Abstract Factory 模式非常像,但是它们之间有着...

    C#视频-面向对象设计模式纵横谈(4):Builder 生成器模式(创建型模式)

    Builder模式是一种创建型设计模式,它提供了一种...在观看“C#视频-面向对象设计模式纵横谈(4):Builder 生成器模式(创建型模式)”的视频教程时,可以深入理解Builder模式的工作原理,学习如何在实际项目中有效应用。

    iOS设计模式-生成器

    生成器模式通常由四个组件构成:Director(导演)、ConcreteBuilder(具体生成器)、Product(产品)和Builder(构建者)。Director负责协调和指导构建过程,ConcreteBuilder实现了具体的构建步骤,并返回一个...

Global site tag (gtag.js) - Google Analytics