设计模式之生成器

  1. 定义
    将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以使用不同的表示

  2. 结构和说明

    这里写图片描述

    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部件
        }
    }
  3. 导出数据的应用框架
    对于导出数据的应用框架,导出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();
        }
    }
  4. 生成器模式功能

    生成器模式主要功能是构建复杂的产品而且是细化的,分步构建产品,重在解决一步一步构造复杂对象。
    构建的过程是统一的,固定不变的,变化的部分放到生成器中。生成器的重心在于分离构建算法和具体的构造实现,从而使得构建算法可以重用,具体的构造实现可以很方便的扩展和切换。

  5. 生成器模式构成
    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实现中获取最终装备好的产品

  6. 生成器构建复杂对象

    实际应用,要创建一个保险合同的对象,里面有很多属性值都有约束,要求创建出来的对象是满足这些约束规则的。保险合同通常情况下可以和个人签订,也可以和公司签订,互斥约束。

        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); 
                }
            }
    
        }
  7. 生成器模式的优缺点

    a. 松散耦合
    b. 可以很容易的改变产品内部展示
    c. 更好的复用性
    
  8. 本质

    分离整体构建算法和部件构造
    
  9. 使用场景

    a.如果创建对象的算法,应该独立与该对象的组成部分以及他们的装配方式。
    b.如果同一个构建过程有着不同的表示。
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值