跟屌丝大哥学习设计模式--生成器模式(Builder)

简介:

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
           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");
         }
     @Override
          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");
        }

      @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/

目录
相关文章
|
3月前
|
设计模式 前端开发 搜索推荐
前端必须掌握的设计模式——模板模式
模板模式(Template Pattern)是一种行为型设计模式,父类定义固定流程和步骤顺序,子类通过继承并重写特定方法实现具体步骤。适用于具有固定结构或流程的场景,如组装汽车、包装礼物等。举例来说,公司年会节目征集时,蜘蛛侠定义了歌曲的四个步骤:前奏、主歌、副歌、结尾。金刚狼和绿巨人根据此模板设计各自的表演内容。通过抽象类定义通用逻辑,子类实现个性化行为,从而减少重复代码。模板模式还支持钩子方法,允许跳过某些步骤,增加灵活性。
159 11
|
2天前
|
设计模式 Java 关系型数据库
设计模式:工厂方法模式(Factory Method)
工厂方法模式是一种创建型设计模式,通过将对象的创建延迟到子类实现解耦。其核心是抽象工厂声明工厂方法返回抽象产品,具体工厂重写该方法返回具体产品实例。适用于动态扩展产品类型、复杂创建逻辑和框架设计等场景,如日志记录器、数据库连接池等。优点包括符合开闭原则、解耦客户端与具体产品;缺点是可能增加类数量和复杂度。典型应用如Java集合框架、Spring BeanFactory等。
|
4月前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
|
2月前
|
设计模式
「全网最细 + 实战源码案例」设计模式——模式扩展(配置工厂)
该设计通过配置文件和反射机制动态选择具体工厂,减少硬编码依赖,提升系统灵活性和扩展性。配置文件解耦、反射创建对象,新增产品族无需修改客户端代码。示例中,`CoffeeFactory`类加载配置文件并使用反射生成咖啡对象,客户端调用时只需指定名称即可获取对应产品实例。
92 40
|
6月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。
|
2月前
|
设计模式 关系型数据库
「全网最细 + 实战源码案例」设计模式——简单工厂模式
简单工厂模式是一种创建型设计模式,通过工厂类根据传入参数创建不同类型的对象,也称“静态工厂方法”模式。其结构包括工厂类、产品接口和具体产品类。优点是封装性强、代码复用性好;缺点是扩展性差,增加新产品时需修改工厂类代码,违反开闭原则。适用于对象种类较少且调用者无需关心创建细节的场景。
64 19
|
6月前
|
设计模式 算法
设计模式--建造者模式 builder
这篇文章通过一个电脑购买的例子,详细解释了建造者模式的四个角色(产品类、抽象构建者、实体构建类和指导者类),并提供了相应的代码实现,阐述了建造者模式在设计复杂对象时的应用和优势。
设计模式--建造者模式 builder
|
2月前
|
设计模式 Java
「全网最细 + 实战源码案例」设计模式——生成器模式
生成器模式(Builder Pattern)是一种创建型设计模式,用于分步骤构建复杂对象。它允许用户通过控制对象构造的过程,定制对象的组成部分,而无需直接实例化细节。该模式特别适合构建具有多种配置的复杂对象。其结构包括抽象建造者、具体建造者、指挥者和产品角色。适用于需要创建复杂对象且对象由多个部分组成、构造过程需对外隐藏或分离表示与构造的场景。优点在于更好的控制、代码复用和解耦性;缺点是增加复杂性和不适合简单对象。实现时需定义建造者接口、具体建造者类、指挥者类及产品类。链式调用是常见应用方式之一。
61 12
|
2月前
|
设计模式 关系型数据库
「全网最细 + 实战源码案例」设计模式——工厂方法模式
简单工厂模式是一种创建型设计模式,通过一个工厂类根据传入参数创建不同类型的产品对象,也称“静态工厂方法”模式。其结构包括工厂类、产品接口和具体产品类。适用于创建对象种类较少且调用者无需关心创建细节的场景。优点是封装性强、代码复用性好;缺点是扩展性差,增加新产品时需修改工厂类代码,违反开闭原则。
56 15
|
4月前
|
设计模式 开发者 Python
Python编程中的设计模式:工厂方法模式###
本文深入浅出地探讨了Python编程中的一种重要设计模式——工厂方法模式。通过具体案例和代码示例,我们将了解工厂方法模式的定义、应用场景、实现步骤以及其优势与潜在缺点。无论你是Python新手还是有经验的开发者,都能从本文中获得关于如何在实际项目中有效应用工厂方法模式的启发。 ###