生成器模式(Builder)

1. 模式的定义

不管是输出成文本文件,还是输出到XML文件,在实现的时候,步骤基本都是一样的,大致可以分为以下四步:

1)先拼接文件头的内容

2)然后拼接文件体的内容

3)再拼接文件尾的内容

4)最后拼接好的内容输出称为文件

换句话说,也就是构建每种格式的数据文件的处理过程,应该和具体的步骤实现分开,这样能够复用处理过程。

生成器模式的定义:将一个复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建不同的表示。

2. UML图

Builder:生成器接口,定义创建一个Product对象所需的各个部件的操作

ConcreteBuilder:具体的生成器实现,实现各个部件的创建,并负责组装Product对象的部件,同时还提供一个让用户获取组装完成后的产品对象的方法

Director:指导者,主要用来使用Builder接口,以一个统一的过程来构建所需要的Product对象

Product:产品,表示被生成器构建的复杂对象,包含多个部件

代码:

对同一个构建过程,只要配置不同的生成器实现,就会生成不同实现的对象。

/**
 * 描述输出到文件头的内容的对象
 */
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;
    }
}

/**
 * 描述输出数据的对象
 */
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;
    }

}

/**
 * 描述输出到文件尾的内容的对象
 */
public class ExportFooterModel {
    /**
     * 输出人
     */
    private String exportUser;

    public String getExportUser() {
        return exportUser;
    }

    public void setExportUser(String exportUser) {
        this.exportUser = exportUser;
    }

}

/**
 * 构建器接口,定义创建一个输出文件对象所需的各个部件的操作
 */
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();
    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;
    }
}

/**
 * 实现导出数据到XML文件的的构建器对象
 */
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;
    }

}

/**
 * 指导者,指导使用构建器的接口来构建输出的文件的对象
 */
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);
    }
}

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();//1
        //创建指导者对象
        Director director = new Director(txtBuilder);
        director.construct(ehm, mapData, efm);
        //把要输出的内容输出到控制台看看
        System.out.println("输出到文本文件的内容:\n"+txtBuilder.getResult());
        //测试输出到xml文件
        XmlBuilder xmlBuilder = new XmlBuilder();//2
        Director director2 = new Director(xmlBuilder);
        director2.construct(ehm, mapData, efm);
        //把要输出的内容输出到控制台看看
        System.out.println("输出到XML文件的内容:\n"+xmlBuilder.getResult());
    }
}

3. 研磨设计模式

生成器模式重在一步一步解决构造复杂对象的问题。这个构建过程是统一的,固定不变的,变化的部分放到生成器部分了,只要配置不同的生成器,那么同样的构建过程,就能构建出不同的产品来。

生成器模式的重心在于分离构建算法与具体的构造实现。

生成器模式的本质:分离整体构建算法和部件构建

构建保险合同对象:

/**
 * 保险合同的对象
 */
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){
        this.contractId = builder.contractId;
        this.personName = builder.personName;
        this.companyName = builder.companyName;
        this.beginDate = builder.beginDate;
        this.endDate = builder.endDate;
        this.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;
        /**
         * 构造方法,传入必须要有的参数
         * @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;
        }
        /**
         * 构建真正的对象并返回
         * @return 构建的保险合同的对象
         */
        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(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);
        }
    }

    /**
     * 示意:保险合同的某些操作
     */
    public void someOperation(){
        System.out.println("Now in Insurance Contract someOperation=="+this.contractId);
    }
}

public class Client {
    public static void main(String[] args) {
        //创建构建器
        InsuranceContract.ConcreteBuilder builder = new InsuranceContract.ConcreteBuilder("001",12345L,67890L);
        //设置需要的数据,然后构建保险合同对象
        InsuranceContract contract = builder.setPersonName("张三").setOtherData("test").build();
        //操作保险合同对象的方法
        contract.someOperation();
    }
}
时间: 2024-11-08 16:26:08

生成器模式(Builder)的相关文章

模式02 生成器模式(Builder)

1. 意图 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 2. 结构 此模式的结构如下图所示. 3. 参与者 Builder-- 为创建一个Product对象的各个部件指定抽象接口. ConcreteBuilder-- 实现Builder的接口以构造和装配该产品的各个部件.-- 定义并明确它所创建的表示.-- 提供一个检索产品的接口. Director-- 构造一个使用Builder接口的对象. Product-- 表示被构造的复杂对象.ConcreteBuilde

生成器模式(Builder Pattern)

一. 建造者(Builder)模式 建造者模式可以将一个产品的内部表象与产品的生成过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象. 对象性质的建造 有些情况下,一个对象会有一些重要的性质,在它们没有恰当的值之前,对象不能作为一个完整的产品使用.比如,一个电子邮件有发件人地址.收件人地址.主题.内容.附录等部分,而在最起码的收件人地址未被赋值之前,这个电子邮件不能发出. 有些情况下,一个对象的一些性质必须按照某个顺序赋值才有意义.在某个性质没有赋值之前,另一个性质则无法赋值.

[设计模式]&lt;2&gt;. C++与生成器模式(Builder pattern)

原文地址: http://www.cnblogs.com/hebaichuanyeah/p/5585957.html 当构建一个复杂对象时,将构建过程与表示分离.使得同样的过程创建不同的对象. 简单例子,构建produce类,需要构建三个部分part1,part2,part3.通过build类去构建它们,并返回.通过director 类调用build对象进行配置. C++代码 #include <iostream> using namespace std; class Produce { pu

每天一个设计模式-7 生成器模式(Builder)

每天一个设计模式-7 生成器模式(Builder) 一.实际问题 在讨论工厂方法模式的时候,提到了一个导出数据的应用框架,但是并没有涉及到导出数据的具体实现,这次通过生成器模式来简单实现导出成文本,Xml等具体的格式. 导出成文本或Xml等格式的数据时,一般都会有各自的格式,比如:导出的文件都有3个部分,文件头,内容,尾. 二.问题分析 无论哪种导出格式,都需要3个部分,文件头,内容,尾等信息,并且他们的内容相同.即他们的构造算法固定,只是生成的结果不同:能不能把算法(构建)和结果(外观)分离出

创建型-生成器模式(Builder)

1.意图: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 2.场景描述: 编辑软件的“另存为”功能便是生成器模式的一个体现.例如,Word的另存为功能,可以选择将文件存储为doc.docx.pdf.txt等格式,但是通过word的另存为功能转变文档的存储格式时都采用了“文件 --> 另存为”,相同的创建过程.当需要对word支持新的类型转换时,例如,添加*.newtype类型的转换,此时只需在“另存为”对话框的“选择存储类型”中添加一行"*.newtype&q

跟着实例学习设计模式-生成器模式(builder)

生成器模式是创建型设计模式. 设计意图:将一个复杂的类表示与其构造相分离,使得相同的构建过程能够得出不同的表示. 实例类图: IVehicleBuilder:抽象建造者,为创建一个Vehicle对象并创建它的相关部件指定的抽象接口,把产品的生产过程分解为不同的步骤,从而使具体的建造者在具体的建造步骤上具有更多弹性,从而创造出不同表示的产品.(这里就是小车和卡车) CarBuilder.TrunkBuilder:具体建造者,实现IVehicleBuilder接口,构造和装配产品的各个部件定义并明确

生成器模式(Builder)-- 对象创建型模式

1. 动机 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.一个RTF(Rich Text Format)文档交换格式的阅读器应能将RTF转换为多种正文格式.该阅读器可以将RTF文档转换成普通ASCII文本或转换成一个能以交互方式编辑的正文窗口组件.但问题在于可能转换的数目是无限的.因此要能够很容易实现新的转换的增加,同时却不改变RTF阅读器.其实也就是,前面的数据接卸(源头处理)归解析,后续的显示处理,由显示处理的部分来完成.在数据解析和显示处理之间架设一个标准的桥梁

设计模式(二): BUILDER生成器模式 -- 创建型模式

1.定义 将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式. 2.适用场景 1. 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时. 2. 当构造过程必须允许被构造的对象有不同表示时. 3.评价 1. 它使你可以改变一个产品的内部表示. Builder对象提供给导向器一个构造产品的抽象接口.该接口使得生成器可以隐藏这个产品的表示和内部结构.它同时也隐藏了该产品是如何装配的.因为产品是通过抽象接口构造的,你在改变该产品的内部表

实战生成器模式(Builder Pattern In Practice)

原文链接:http://www.javacodegeeks.com/2013/01/the-builder-pattern-in-practice.html 我不会详细介绍这个模式,因为已经有大量的文章或者书籍对该模式进行过详细的解析.我将告诉你的是为什么以及什么时候你应该考虑使用它.值得一提的是,我所介绍的这个模式和设计模式四人帮的书(<设计模式:可复用面向对象软件的基础>)里面的有些许区别.四人帮书里面介绍的生成器模式重点在抽象出对象创建的步骤,并通过调用不同的具体实现从而得到不同的结果,