本文共 7822 字,大约阅读时间需要 26 分钟。
Builder 模式的重心在于分离构建算法和具体的构造实现,从而使构建算法可以重用。
Builder 模式的构成分为两部分:一部分是Builder接口,定义了如何构建各个部件,并装配到产品中去;另一部分是Director,定义如何来构建产品,Director 负责整体的构建算法,而且通常是分步来执行的。
注:这里的构建算法是指:通过什么样的方式来组装产品;构建产品指的是:构建一个复杂对象。
Builder 模式就是将构建产品部件和组装产品的过程分开,即实现了产品部件和组装产品过程的解耦,可以使得组装产品过程得到复用
public class ExportHeaderModel {
private String depId;
private String exportDate; 省略getter 和 setter }public class ExportDataModel {
private String productId;
private double price; private double amount; 省略getter 和 setter }public class ExportFooterModel {
private String exportUser;
省略getter 和 setter
}
/** * 生成器接口,定义一个输出文件对象所需的各个部件的操作 * */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); }/**
* 实现导出数据到文本文件的生成器 * */public class TxtBuilder implements Builder {
/**
* 用来记录构建文件的内容,相当于产品 */ private StringBuffer buffer = new StringBuffer(); @Override public void buildHeader(ExportHeaderModel ehm) { buffer.append(ehm.getDepId() + "," + ehm.getExportDate() + "\n"); }@Override
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"); } } }@Override
public void buildFooter(ExportFooterModel efm) { buffer.append(efm.getExportUser()); }public StringBuffer getResult(){
return buffer; } }public class XmlBuilder implements Builder {
private StringBuffer buffer = new StringBuffer();
@Override@Override
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 StringBuffer getResult(){
return buffer; } }/**
* 指导者,指导使用生成器的接口来构建输出的文件对象 */**
* 指导者,指导使用生成器的接口来构建输出的文件对象 * */public class Director {/**
* 持有当前需要使用的生成器对象 */ private Builder 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){ //构建Header builder.buildHeader(ehm); //构建Body builder.buildBody(mapData); //构建Footer builder.buildFooter(efm); } }public class Client {
public static void main(String[] args) {
ExportHeaderModel ehm = new ExportHeaderModel(); ehm.setDepId("一分公司"); ehm.setExportDate("2011-06-12"); Map<String, Collection<ExportDataModel>> mapData = new HashMap<String, Collection<ExportDataModel>>(); Collection<ExportDataModel> coll = new ArrayList<ExportDataModel>(); ExportDataModel edml = new ExportDataModel(); edml.setAmount(80); edml.setProductId("产品001号"); edml.setPrice(100); coll.add(edml); ExportDataModel edm2 = new ExportDataModel(); edm2.setAmount(60); edm2.setProductId("产品002号"); edm2.setPrice(120); coll.add(edm2); mapData.put("销售记录表", coll); 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()); XmlBuilder xmlBuilder = new XmlBuilder(); Director director2 = new Director(xmlBuilder); director2.construct(ehm, mapData, efm); System.out.println("输出到Xml文件的内容:\n" + xmlBuilder.getResult()); }}
● 使用生成器模式创建复杂对象:
① 由于使用Builder 模式来创建某个对象,因此就没有必要再定义一个Builder接口,直接提供一个具体的构建器类就可以了。
② 对于创建一个复杂的对象,可能会有很多种不同的选择和步骤,干脆去掉“Director”,把Director的功能和Client 的功能合并起来,也就是说这个时候,Client 相当于指导者,它来指导构建器类去构建需要的复杂对象。
public class ConcreteBuilder {
private String contractId;
private String personName; private String companyName; private long beginDate; private long endDate; private String otherData; /** * 构造方法 传入必填数据 * @param contractId 保险合同号 * @param beginDate 保险开始生效的日期 * @param endDate 保险失效的日期 */ public ConcreteBuilder(String contractId, long beginDate, long endDate){ this.contractId = contractId; this.beginDate = beginDate; this.endDate = endDate; } /** * 选填数据,被保险人 * @param personName 被保险人名 * @return 构建对象 */ public ConcreteBuilder setPersonName(String personName){ this.personName = personName; return this; } /** * 选填数据,被保险公司 * @param companyName 被保险公司名 * @return 构建对象 */ public ConcreteBuilder setCompanyName(String companyName){ this.companyName = companyName; return this; } /** * 选填数据,其它数据 * @param otherData 其它数据 * @return 构建对象 */ public ConcreteBuilder setOtherData(String otherData){ this.otherData = otherData; 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 = (companyName != null && companyName.trim().length() > 0); if(!(signPerson ^ signCompany)){ 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); } public String getContractId() { return contractId; } public String getPersonName() { return personName; } public String getCompanyName() { return companyName; } public long getBeginDate() { return beginDate; } public long getEndDate() { return endDate; } public String getOtherData() { return otherData; } }/**
* 保险合同对象 * @author joe * */public class InsuranceContract {/**
* 保险合同编号 */ private String constractId; /** * 被保险的人 */ private String personName; /** * 被保险的公司 */ private String companyName; /** * 保险开始生效的日期 */ private long beginDate; /** * 保险失效的日期 */ private long endDate; /** * 其它数据 */ private String otherData; /** * 构造方法,访问级别是同包能访问 * @param builder */ InsuranceContract(ConcreteBuilder builder){ this.constractId = builder.getContractId(); this.personName = builder.getPersonName(); this.companyName = builder.getCompanyName(); this.beginDate = builder.getBeginDate(); this.endDate = builder.getEndDate(); this.otherData = builder.getOtherData(); } public void someOperation(){ System.out.println("Now in Insurance Contract someOperation == " + this.constractId); }}
public class Client {
public static void main(String[] args) {
ConcreteBuilder builder = new ConcreteBuilder("001", 82345L, 67890L); InsuranceContract contract = builder.setPersonName("张三").setOtherData("test").build(); contract.someOperation(); } }
====================================分割线================================
最新内容请见作者的GitHub页:http://qaseven.github.io/
转载地址:http://epega.baihongyu.com/