• 设计模式之(五)建造者(生成器)模式(Builder)


      考虑这样一种业务场景,我们构建一个业务对象,但是这个业务对象及其复杂。为了代码的根号的可读性,我们会把这个对象的构建过程根据精密联系的程度来拆分成几个类来完成。最后再放到一起使用来生成复杂对象。这个业务场景非常常见,接下来就分析一下解决这个问题更灵活的方式,即:建造者模式。

      建造者模式定义及规范代码

      将一个复杂对象的创建与它的表示分离,使得同样的创建过程可以创建不同的表示。

      看到这个定义以后,肯定有很多读者会有疑问,【复杂对象的创建】的创建好理解,但是【(复杂对象)的表示】是什么意思呢,这里为了解决读者可能出现猴急的心情,先大概解释一下。首先看建造者模式的结构图

                

      Builder:生成器接口,定义创建一个产品所需要的的各个部分的操作。

      ConcreateBuilder:具体的生成器实现,这个产品在组装过程中各个部分所需要的共同的操作。并且还提供一个供用户获取组装完产品的对象。

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

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

      接下来说下我的理解。建造者模式在创建相似的复杂对象使用,其中 Builder 定义创建这个复杂对象的过程,把创建过程分为不同的部分,也可以说是不同的组成部分。而 ConcreateBuilder 则是对复杂对象创建每部分共同的部分实现出来。

         相似复杂对象的每步骤相似部分在 ConcreateBuilder 创建,而不同部分则另外创建,以参数形式传入相应的部分。这个具体如何组装,则是在 Director 中来完成。在这个初步理解的基础上。通过以下例子来具体分析。

      1 /**
      2  * 生成器接口,定义创建一个输出文件对象所需的各个部件的操作
      3  * @author Administrator
      4  */
      5 public interface Builder {
      6     
      7     //构建输出的文件头内容
      8     public void builderHeader(ExportHeaderModel ehm);
      9     
     10     //构建输出的文件正文数据内容
     11     public void BuilderBody(Map<String,Collection<ExportDataModel>> bodyData);
     12     
     13     //构建文件尾内容
     14     public void builderFooter(ExportFooterModel efm);
     15 }
     16 
     17 /**
     18  * 描述输出到文件头部内容的对象
     19  */
     20 public class ExportHeaderModel {
     21     
     22     /**
     23      * 分公司或门市店的编号
     24      */
     25     private String DepID;
     26     
     27     /**
     28      * 导出数据的日期
     29      */
     30     private String exportDate;
     31 
     32     public String getDepID() {
     33         return DepID;
     34     }
     35 
     36     public void setDepID(String depID) {
     37         DepID = depID;
     38     }
     39 
     40     public String getExportDate() {
     41         return exportDate;
     42     }
     43 
     44     public void setExportDate(String exportDate) {
     45         this.exportDate = exportDate;
     46     }
     47 }
     48 
     49 /**
     50  * 描述生成文件输的对象
     51  * @author Administrator
     52  *
     53  */
     54 public class ExportDataModel {
     55     
     56     /**
     57      * 成品编号
     58      */
     59     private String productID;
     60     
     61     /**
     62      * 产品价格
     63      */
     64     private double price;
     65     
     66     /**
     67      * 销售数量
     68      */
     69     private double amount;
     70 
     71     public String getProductID() {
     72         return productID;
     73     }
     74 
     75     public void setProductID(String productID) {
     76         this.productID = productID;
     77     }
     78 
     79     public double getPrice() {
     80         return price;
     81     }
     82 
     83     public void setPrice(double price) {
     84         this.price = price;
     85     }
     86 
     87     public double getAmount() {
     88         return amount;
     89     }
     90 
     91     public void setAmount(double amount) {
     92         this.amount = amount;
     93     }
     94 }
     95 
     96 
     97 /**
     98  * 描述输出到文件尾内容的对象
     99  * @author Administrator
    100  *
    101  */
    102 public class ExportFooterModel {
    103     
    104     /**
    105      * 输出人
    106      */
    107     private String exportUser;
    108 
    109     public String getExportUser() {
    110         return exportUser;
    111     }
    112 
    113     public void setExportUser(String exportUser) {
    114         this.exportUser = exportUser;
    115     }
    116 }
    117 
    118 /**
    119  * 相当于 ConcreteBuilder
    120  * @author Administrator
    121  *
    122  */
    123 public class TxtBuilder implements Builder {
    124 
    125     //用来构建文件的内容,相当于产品
    126     private StringBuffer buffer = new StringBuffer();
    127     
    128     @Override
    129     public void builderHeader(ExportHeaderModel ehm) {
    130         // TODO Auto-generated method stub
    131         buffer.append("分公司编号:"+ehm.getDepID()+",导入日期:"+ehm.getExportDate()+"
    ");
    132     }
    133 
    134     @Override
    135     public void BuilderBody(Map<String, Collection<ExportDataModel>> bodyData) {
    136         // TODO Auto-generated method stub
    137         for(String tblName:bodyData.keySet()){
    138             buffer.append(tblName+"
    ");
    139             for(ExportDataModel edm:bodyData.get(tblName)){
    140                 buffer.append(edm.getProductID()+",  "+edm.getPrice()+", "+edm.getAmount()+"
    ");
    141             } 
    142         }
    143     }
    144 
    145     @Override
    146     public void builderFooter(ExportFooterModel efm) {
    147         // TODO Auto-generated method stub
    148         buffer.append(efm.getExportUser()+"
    ");
    149     }
    150     
    151     public StringBuffer getResult(){
    152         return buffer;
    153     }
    154 }
    155 
    156 
    157 /**
    158  * 相当于 ConcreteBuilder
    159  * @author Administrator
    160  *
    161  */
    162 public class XmlBuilder implements Builder {
    163 
    164     //用来构建文件的内容,相当于产品
    165     private StringBuffer buffer = new StringBuffer();
    166     
    167     @Override
    168     public void builderHeader(ExportHeaderModel ehm) {
    169         // TODO Auto-generated method stub
    170         buffer.append("<?xml verson='1.0' encoding='gb2312'?>
    ");
    171         buffer.append("<Report>
    ");
    172         buffer.append("   <Header>
    ");
    173         buffer.append("      <DeptID>"+ehm.getDepID()+"</DeptID>
    ");
    174         buffer.append("         <ExportDate>"+ehm.getExportDate()+"</ExportDate>
    ");
    175         buffer.append("   </Header>
    ");
    176     }
    177 
    178     @Override
    179     public void BuilderBody(Map<String, Collection<ExportDataModel>> bodyData) {
    180         // TODO Auto-generated method stub
    181         buffer.append("   <Body>
    ");
    182         for(String tblname:bodyData.keySet()){
    183             buffer.append("   <Dates TableName = ""+tblname+"">
    ");
    184             for(ExportDataModel edm:bodyData.get(tblname)){
    185                 buffer.append("   <Date>
    ");
    186                 buffer.append("       <ProductID> "+edm.getProductID()+"</ProductID>
    ");
    187                 buffer.append("       <Price> "+edm.getPrice()+"</Price>
    ");
    188                 buffer.append("       <Amount> "+edm.getAmount()+"</Amount>
    ");
    189             }
    190         }
    191         buffer.append("   <Body>
    ");
    192     }
    193 
    194     @Override
    195     public void builderFooter(ExportFooterModel efm) {
    196         // TODO Auto-generated method stub
    197         buffer.append("    <Footer>
    ");
    198         buffer.append("        <User>"+efm.getExportUser()+"</User>
    ");
    199         buffer.append("    </Footer>
    ");
    200         buffer.append("</Report>
    ");
    201     }
    202     
    203     public StringBuffer getResult(){
    204         return buffer;
    205     }
    206 
    207 }
    208 
    209 
    210 public class Director {
    211     
    212     private Builder builder;
    213     
    214     public Director(Builder builder){
    215         this.builder = builder;
    216     }
    217     
    218     public void construct(ExportHeaderModel ehm,Map<String,Collection<ExportDataModel>> bodyData,ExportFooterModel efm){
    219         builder.builderHeader(ehm);
    220         
    221         builder.BuilderBody(bodyData);
    222         
    223         builder.builderFooter(efm);
    224     }
    225 }
    226 
    227 
    228 public class Client {
    229     
    230     public static void main(String[] args) {
    231         ExportHeaderModel ehm = new ExportHeaderModel();
    232         ehm.setDepID("0001");
    233         ehm.setExportDate("2019-04-26");
    234         
    235         ExportDataModel edm = new ExportDataModel();
    236         edm.setProductID("cp001");
    237         edm.setPrice(5.56);
    238         edm.setAmount(133333);
    239         
    240         ExportDataModel edm2 = new ExportDataModel();
    241         edm2.setProductID("cp001");
    242         edm2.setPrice(5.56);
    243         edm2.setAmount(133333);
    244         
    245         Map<String,Collection<ExportDataModel>> data = new HashMap<String,Collection<ExportDataModel>>();
    246         Collection<ExportDataModel> collect = new ArrayList<ExportDataModel>();
    247         
    248         collect.add(edm);
    249         collect.add(edm2);
    250         
    251         data.put("bodys", collect);
    252         
    253         ExportFooterModel efm = new ExportFooterModel();
    254         efm.setExportUser("pwg");
    255         
    256         TxtBuilder tb = new TxtBuilder();
    257         Director dr = new Director(tb);
    258         
    259         dr.construct(ehm, data, efm);
    260         
    261         System.out.println("输出到文本文件:"+tb.getResult());
    262         
    263         XmlBuilder xml = new XmlBuilder();
    264         Director dr2 = new Director(xml);
    265         dr2.construct(ehm, data, efm);
    266         
    267         System.out.println("输出到 xml 文件:
    "+xml.getResult());
    268     }
    269     
    270     
    271 }

            上面的代码例子展示了建造者模式的功能。其中为了比较好的展示实现了两个不同的产品,实现了两个不同的表示,而 Director 只是实现了一个,但是通过例子可以看出,如果需要。也可以实现不同 Director ,即产品的组装过程。这样产品就是很灵活的扩展性,并且产品的表示和组建过程解耦。

       进而分析出建造者模式的本事是区分 复杂对象的创建  和  它的表示  。这两个在代码中的体现是 Director  和   XmlBuilder  TxtBuilder。

     分析建造者生成器模式

           建造者模式应用场景:可以灵活的、易扩展的创建复杂对象。而解决的办法就是分离构建算法和具体构造实现。这样在扩展的时候可以根据需要切换 构建算法(Director  )和 具体构造实现 (Builder)。只要抓住了这点,基本就理解了生成器的本质了。

  • 相关阅读:
    windows下安装python模块
    红包demo
    如何查看python 的api
    vscode 与 python 的约会
    默认构造函数
    关于重载
    转类型转换
    asm-offset.h 生成
    debian 7 安装
    emacs 定制进缩风格
  • 原文地址:https://www.cnblogs.com/pengweiqiang/p/10765275.html
Copyright © 2020-2023  润新知