生成器模式(英:Builder Pattern)是一种设计模式,又名:建造模式,是一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。
定义:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
结构:
说明:
Builder:
生成器接口,定义创建一个Product对象所需的各个部件的操作。
ConcreteBuilder:
具体的生成器实现,实现各个部件的创建,并负责组装Product对象的各个部件,同时还提供一个让用户获取组装完成后的产品对象的方法。
Director:
指导者,也被称为导向者,主要用来使用Builder接口,以一个统一的过程来构建所需要的Product对象。
Product:
产品,表示被生成器构建的复杂对象,包含多个部件。
具体代码:
Builder接口:
/** * 类说明: 构建器接口,定义创建一个产品对象所需的各个部件的操作 * Time: 2014-2-8 下午2:49:16 * @author 凯文加内特 * Company: http://weibo.com/u/3165936675 */ public interface Builder { /** * 示意方法,构建某个部件 */ public void buildPart(); }
ConcreteBuilder类:
/** * 类说明: 具体的构建器实现对象 * Time: 2014-2-8 下午2:49:32 * @author 凯文加内特 * Company: http://weibo.com/u/3165936675 */ public class ConcreteBuilder implements Builder { /** * 构建器最终构建的产品对象 */ private Product resultProduct; /** * 获取构建器最终构建的产品对象 * @return 构建器最终构建的产品对象 */ public Product getResult() { return resultProduct; } public void buildPart() { //构建某个部件的功能处理 } }
Director类:
/** * 类说明: 指导者,指导使用构建器的接口来构建产品的对象 * Time: 2014-2-8 下午2:50:36 * @author 凯文加内特 * Company: http://weibo.com/u/3165936675 */ public class Director { /** * 持有当前需要使用的构建器对象 */ private Builder builder; /** * 构造方法,传入构建器对象 * @param builder 构建器对象 */ public Director(Builder builder) { this.builder = builder; } /** * 示意方法,指导构建器构建最终的产品对象 */ public void construct() { //通过使用构建器接口来构建最终的产品对象 builder.buildPart(); } }
Product类:
/** * 类说明: 被构建的产品对象的接口 * Time: 2014-2-8 下午2:50:54 * @author 凯文加内特 * Company: http://weibo.com/u/3165936675 */ public interface Product { //定义产品的操作 }
具体案例:
导出文件到txt和xml
/** * 类说明: 描述输出到文件头的内容的对象 * Time: 2014-2-8 下午2:53:05 * @author 凯文加内特 * Company: http://weibo.com/u/3165936675 */ 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; } }
/** * 类说明: 描述输出数据的对象 * Time: 2014-2-8 下午2:52:28 * @author 凯文加内特 * Company: http://weibo.com/u/3165936675 */ 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; } }
/** * 类说明: 描述输出到文件尾的内容的对象 * Time: 2014-2-8 下午2:52:49 * @author 凯文加内特 * Company: http://weibo.com/u/3165936675 */ public class ExportFooterModel { /** * 输出人 */ private String exportUser; public String getExportUser() { return exportUser; } public void setExportUser(String exportUser) { this.exportUser = exportUser; } }
/** * 类说明: 构建器接口,定义创建一个输出文件对象所需的各个部件的操作 * Time: 2014-2-8 下午2:51:37 * @author 凯文加内特 * Company: http://weibo.com/u/3165936675 */ 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); }
/** * 类说明: 实现导出数据到文本文件的的构建器对象 * Time: 2014-2-8 下午2:53:21 * @author 凯文加内特 * Company: http://weibo.com/u/3165936675 */ import java.util.Collection; import java.util.Map; 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; }
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; } }
/** * 类说明: 指导者,指导使用构建器的接口来构建输出的文件的对象 * Time: 2014-2-8 下午2:52:14 * @author 凯文加内特 * Company: http://weibo.com/u/3165936675 */ 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); } }
/** * 类说明: * Time: 2014-2-8 下午2:51:54 * @author 凯文加内特 * Company: http://weibo.com/u/3165936675 */ 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()); } }
使用场景:
当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时;
当构造过程必须允许被构造的对象有不同的表示时。
优点和缺点:
1.松散耦合,同一构建算法结构构建出表现完全不同的对象,实现对象构建跟对象表现上的分离;
2.很容易改变产品的内部表示,相对Director来说,产品内部变化不影响Director
3.复用,构建算法和具体实现都可以被复用
留给自己的问题:
与模板模式的区别,生成器模式是分离复杂对象的构建算法和具体实现,模板定义算法骨架,把某些步骤延迟到子类去实现