定义
将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以使用不同的表示结构和说明
Builder 生成器接口,定义创建一个Product对象所需要的各个部件的操作。
ConcreteBuilder 具体生成器实现,实现各个部件的创建。并负责组装Product对象的各个部件,同时还提供一个组装完整的Product对象。
Director 指导者,主要使用Builder接口,以一个统一的过程来构建所需要的Product对象
Product 产品,表示被生成器构建的复杂对象,包含对个部件。public interface Builder { public void buildPart(); } public interface Product{ //定义产品接口操作 } public class Director{ private Builder builder; public Director(Builder builder){ this.builder = builder; } public void constuct(){ builder.buildPart(); } } public class ConcreteBuilder implements Builder{ private Product product; public Product getResult{ return product; } public void buildPart(){ //构建product部件 } }
导出数据的应用框架
对于导出数据的应用框架,导出txt文件和xml文件 通常对于具体的导出内容和格式是有要求
1.导出文件分别文件头,文件体和文件尾
2.文件头中:分公司或市点变好,导出数据日期,对于文本格式,用逗号分隔
3.文件体部分,需要表名称,分条描述数据
4.文件尾中:输出人public class ExportHeaderModel{ private String depId; private Date exportDate; } public class ExportDataModel{ private String productId; private Integer productNum; private double price; } public class ExportFooterModel{ private String operatorUser; } public interface Builder{ public void buildHeader(); public void buildBody(); public void buildFooter(); } public class TxtBuilder implements Builder{ private StringBuilder buffer = new StringBuilder(); public void buildHeader(ExportHeaderModel ehm){ buffer.append(ehm.getDepId()+","ehm.getExportData()+"\n"); } public void buildBody(Map<String,Collection<ExportDataModel>> mapData){ for (String tbName : mapData.keySet()){ buffer.append(tbName+"\n"); for (ExportDataModel edm:mapData.get(tbName)){ buffer.append(edm.getProductId()+","+edm.getPrice()+","+edm.getPriceNum()+"\n"); } } } public void buildFooter(ExportFooterModel efm){ buffer.append(efm.getExportUser()); } public StringBuilder getResult(){ return buffer; } } public class XmlBuilder implements Builder{ private StringBuilder buffer = new StringBuilder(); public void buildHeader(ExportHeaderModel ehm){ buffer.append("<xml version='1.0' encoding='gb2313' ?>\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 void buildBody(Map<String,Collection<ExportDataModel>> mapData){ //略 buffer.append(""); } 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 StringBuilder getResult(){ return stringBuilder; } } public class Director{ private Builder builder; public Director(Builder builder){ this.builder = builder; } public void constuct(){ builder.buildHeader(); builder.buildBody(); builder.buildFooter(); } } public class client { public static void main(String[]args){ TxtBuilder txtBuilder = new TxtBuilder(); Director director = new Director(txtBuilder); StringBuilder stringBuilder = txtBuilder.getResult(); } }
生成器模式功能
生成器模式主要功能是构建复杂的产品而且是细化的,分步构建产品,重在解决一步一步构造复杂对象。
构建的过程是统一的,固定不变的,变化的部分放到生成器中。生成器的重心在于分离构建算法和具体的构造实现,从而使得构建算法可以重用,具体的构造实现可以很方便的扩展和切换。生成器模式构成
builder接口定义如何构建各个部件,也只到每个功能如何实现,以及如何配置这些部件到产品中
Director是知道如何来构建产品也就是说director 负责整体的构建算法而且通常是分步骤来执行。生成器模式中,强调固定整体的构建算法,而灵活扩展和切换部件的具体构造和产品的装配方式,Director实现整体构建算法时候,遇到需要创建和组合具体部件时候会通过委托方式,交给Builder去完成。Builder接口实现中,每个部件的构建方法里面,除了部件装配外,也可以实现具体创建各个部件对象,也就是说每个方法都可以有两部分,一个是创建部件对象,一个是组装部件。
在构建部件的方法里面可以选择实现并创建部件对象,然后在把这个部件对象装到产品中去—>Builder和工厂方法配合使用。public class MyFooter{ public String genHeader(ExportFooterModel efm){ StringBuilder buffer = new StringBuilder(); buffer.append(" <Footer>\n"); buffer.append(" <ExportUser>"+efm.getExportUser()+"</ExportUser>\n"); buffer.append(" </Footer>\n"); buffer.append("<Report>\n"); return buffer.toString(); } } public class FooterFactory{ public static MyFooter createMyFooter(){ // return new MyFooter(); } } public class XmlBuilder implements Builder{ private StringBuilder buffer = new StringBuilder(); public void buildHeader(ExportHeaderModel ehm){ buffer.append("<xml version='1.0' encoding='gb2313' ?>\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 void buildBody(Map<String,Collection<ExportDataModel>> mapData){ //略 buffer.append(""); } public void buildFooter(ExportFooterModel efm){ //不是由自己来创建对象,而是使用其他组建创建对象 //比如简单工厂,工厂方法 MyFooter mf = FooterFactory.createMyFooter(); buffer.append(mf.genHeader(efm)); } public StringBuilder getResult(){ return stringBuilder; } }
指导者是把变化的部分分离出去。真正的指导者实现,应该是有较为复杂的算法和运算过程,在运算过程中根据需要才会有调用生成器的方法来生成部件对象。
指导者和生成器是需要交互的,方式通过生成器方法的参数和返回值,来回的传递数据,事实上指导者是通过委托的方式把功能交给生成器去完成。在标准的生成器中,在Builder 实现中会提供一个返回装配好的产品方法,在Builder 接口中是没有的。指导者不负责具体的部件创建和组装,客户端是从Builder实现中获取最终装备好的产品。
生成器构建复杂对象
实际应用,要创建一个保险合同的对象,里面有很多属性值都有约束,要求创建出来的对象是满足这些约束规则的。保险合同通常情况下可以和个人签订,也可以和公司签订,互斥约束。
public class InsuranceContract{ private String contractId; //保险只能和个人签订,或者和公司签订 private String personName; private String companyName; private long beginDate; //保险失效日期一定大于保险开始生效日期 private long endDate; private String data; //构造方法默认级别,同包都可访问 InsuranceContract(ConcreteBuilder builder){ this.contractId = builder.getContractId(); this.personName = builder.getPersonName(); this.companyName = builder.getCompanyName(); this.beginDate = builder.getBeginDate(); this.endDate = builder.getEndDate(); this.data = builder.getData(); } public void someOperation(){ } } public class ConcreteBuilder{ private String contractId; private String personName; private String companyName; private long beginDate; private long endDate; private String data; public ConcreteBuilder(String contractId,long beginDate,long endDate){ this.contractId = contractId; this.beginDate = beginDate; this.endDate = endDate; } public ConcreteBuilder setPersonName(String personName){ this.personName = personName; return this; } public ConcreteBuilder setCompanyName(String companyName){ this.companyName = companyName; return this; } public InsuranceContract build(){ if (contractId == null || contractId.trim().length()==0){ throw new IllegalArgumentException("合同编号不能为空"); } boolean signPerson = personName != null && personName.trim().length() > 0; boolean signCompany = signCompany != null && signCompany.trim().length() > 0; if ( signPerson && signCompany){ throw new IllegalArgumentException("一份保险不能同时与人和公司签订"); } if (signPerson == false && signCompany==false){ throw new IllegalArgumentException("一份保险必须有签订对象"); } if (beginDate <=0){ throw new IllegalArgumentException("合同必须有开始生效时间"); } if (endDate<=0){ throw new IllegalArgumentException("合同必须有保险失效时间"); } if (endDate<=beginDate){ throw new IllegalArgumentException("合同保险时间必须小于失效时间"); } return new InsuranceContract(this); } //问题:?同包是可以直接new InsuranceContract对象的 //InsuranceContract ic = new InsuranceContract(new builder()); } //解决方案 构建器对象 public class InsuranceContract{ private String contractId; //保险只能和个人签订,或者和公司签订 private String personName; private String companyName; private long beginDate; //保险失效日期一定大于保险开始生效日期 private long endDate; private String data; //构造器私有 private InsuranceContract(ConcreteBuilder builder){ this.contractId = builder.getContractId(); this.personName = builder.getPersonName(); this.companyName = builder.getCompanyName(); this.beginDate = builder.getBeginDate(); this.endDate = builder.getEndDate(); this.data = builder.getData(); } public static class ConcreteBuilder{ private String contractId; private String personName; private String companyName; private long beginDate; private long endDate; private String data; public ConcreteBuilder(String contractId,long beginDate,long endDate){ this.contractId = contractId; this.beginDate = beginDate; this.endDate = endDate; } public ConcreteBuilder setPersonName(String personName){ this.personName = personName; return this; } public ConcreteBuilder setCompanyName(String companyName){ this.companyName = companyName; return this; } public InsuranceContract build(){ if (contractId == null || contractId.trim().length()==0){ throw new IllegalArgumentException("合同编号不能为空"); } boolean signPerson = personName != null && personName.trim().length() > 0; boolean signCompany = signCompany != null && signCompany.trim().length() > 0; if ( signPerson && signCompany){ throw new IllegalArgumentException("一份保险不能同时与人和公司签订"); } if (signPerson == false && signCompany==false){ throw new IllegalArgumentException("一份保险必须有签订对象"); } if (beginDate <=0){ throw new IllegalArgumentException("合同必须有开始生效时间"); } if (endDate<=0){ throw new IllegalArgumentException("合同必须有保险失效时间"); } if (endDate<=beginDate){ throw new IllegalArgumentException("合同保险时间必须小于失效时间"); } return new InsuranceContract(this); } } }
生成器模式的优缺点
a. 松散耦合 b. 可以很容易的改变产品内部展示 c. 更好的复用性
本质
分离整体构建算法和部件构造
使用场景
a.如果创建对象的算法,应该独立与该对象的组成部分以及他们的装配方式。 b.如果同一个构建过程有着不同的表示。
设计模式之生成器
最新推荐文章于 2023-12-25 20:56:38 发布