场景:
考虑导出数据的应用框架,通常在导出的数据形式上有一定的约定方式,对于不同的输出格式,处理步骤都是一样的,但
是每步的具体实现是不一样的,像导出成TXT和EXCEL的文本形式不一样,但是导出的数据都会分为文件头,文件体和文件
尾.所以应该将处理步骤导出文件头,导出文件体,导出文件尾这几个固定步骤提炼出来,形成公共的处理过程.今后可能会
有很多种不同输出格式的要求,这就需要在处理过程不变的情况下,能方便地切换不同的输出格式处理。
定义:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
角色:
Builder:
生成器接口,定义创建一个Product对象所需的各个部件的操作。
package com.kris.study; public interface Builder { public void builderHead(); public void buidlerFoot(); public void buildPart(); }
ConcreteBuilder:
具体的生成器实现,实现各个部件的创建,并负责组装Product对象的各个部件,同时还提供一个让用户获取组装完成后
的产品对象的方法.
package com.kris.study; public class ConcreteBuilder implements Builder { /** * 生成器最终构建的产品对象 */ private Product resultProduct; public Product getResult(){ return resultProduct; } @Override public void buildPart() { //构建某个部件的功能处理 System.out.println("创建身体"); } @Override public void builderHead() { System.out.println("创建头部"); } @Override public void buidlerFoot() { System.out.println("创建腿部"); } }
package com.kris.study; public class ConcreteBuilder2 implements Builder { /** * 生成器最终构建的产品对象 */ private Product resultProduct; public Product getResult(){ return resultProduct; } @Override public void builderHead() { System.out.println("创建触角"); } @Override public void buidlerFoot() { System.out.println("创建躯干"); } @Override public void buildPart() { System.out.println("创建脚"); } }
Director:
指导者,主要用来使用Builder接口,以一个统一的过程来构建所需要的Product对象
package com.kris.study; public class Director { //持有当前需要使用的生成器对象 private Builder builder; public Director(Builder builder){ this.builder = builder; } /** * 指导生成器构建最终的产品对象 */ public void construct(){ builder.builderHead(); builder.buildPart(); builder.buidlerFoot(); }}
Product:
产品,表示生成构建的复杂对象,包含多个部件。
package com.kris.study;
public interface Product { //定义产品的操作 public String foot(); public String head(); public String body(); }
Client:
客户端
package com.kris.study; public class Client { public static void main(String[] args) { Builder builder = new ConcreteBuilder(); Director direc = new Director(builder); direc.construct(); Builder builder2 = new ConcreteBuilder2(); Director direc2 = new Director(builder2); direc2.construct(); } }
原理分析:
生成器模式的主要功能是构建复杂的产品,而且是细化的,分多个固定步骤构建的产品,这个构建的过程是统一的,不变的.
将变化的部分放到生成器部分,只有配置不同的生成器,那么同样的构建过程,就能构建出不同的产品来。
生成器两个很重要的部分:
1.Builder接口,这里定义了如何构建各个部件,也就是知道每个部件的功能如何实现,以及如何装配这些产品
2.Director指导者,Director负责整体的构建算法,知道如何组合来构建完整的产品.
在Director实现整体构建算法时,遇到需要创建和组合具体部件时,就会委托给Builder完成。
在实际应用中需要指导者Director和生成器Builder之间进行交互来构建产品,方式通过生成器方法的参数和返回值,来
回地传递数据。
采用Builder直接构建复杂的对象,通常会对Builder模式进行一定的简化.
1.由于是用Builder模式来创建某个对象,因此没必要再定义一个Builder接口,提供一个具体构建器类就可以了。
2.将指导者和Client功能合并起来,由Client去指导构建器去构造复杂对象
3.将构建器和被构建对象合并,将类内联化。
考虑一个实际应用,要创建一个合同对象,里面有很多属性值都有约束,要求创建出来的对象满足这些约束规则.约束规
则比如,保险合同通常情况下可以和个人签订,也可以和某个公司签订,但是一份合同不能同时与个人和公司签订。
package com.kris.study; public class InsuranceContract { private String contractId; private String personName; private String companyName; private long beginDate; private long endDate; private String otherData; private InsuranceContract(ConcreteBuilder builder){ contractId = builder.contractId; personName = builder.personName; companyName = builder.companyName; beginDate = builder.beginDate; endDate = builder.endDate; otherData = builder.otherData; } public static class ConcreteBuilder{ private String contractId; private String personName; private String companyName; private long beginDate; private long endDate; private String otherData; public ConcreteBuilder(String contractId, long beginDate, long endDate) { super(); 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 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(signCompany && signPerson){ throw new IllegalArgumentException("一份合同不能同时与人和公司签订"); } if(signCompany == false && signPerson == 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); } } public void someOperation(){ System.out.println("Now in Insurance Contract someOperation =="+this.contractId); } }
package com.kris.study; public class Client { public static void main(String[] args) { InsuranceContract.ConcreteBuilder builder = new InsuranceContract.ConcreteBuilder("101", 102L, 67890L); InsuranceContract contract = builder.setPersonName("张三"). setOtherData("test").build(); contract.someOperation(); } }
优点:
松散耦合,更好的复用性,将构建算法和具体产品实现分离,这样使得构建产品的算法可以复用。
本质: 分离整体构建算法和部件构造