设计模式之(五)建造者(生成器)模式(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()+"\n");
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+"\n");
139             for(ExportDataModel edm:bodyData.get(tblName)){
140                 buffer.append(edm.getProductID()+",  "+edm.getPrice()+", "+edm.getAmount()+"\n");
141             } 
142         }
143     }
144 
145     @Override
146     public void builderFooter(ExportFooterModel efm) {
147         // TODO Auto-generated method stub
148         buffer.append(efm.getExportUser()+"\n");
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'?>\n");
171         buffer.append("<Report>\n");
172         buffer.append("   <Header>\n");
173         buffer.append("      <DeptID>"+ehm.getDepID()+"</DeptID>\n");
174         buffer.append("         <ExportDate>"+ehm.getExportDate()+"</ExportDate>\n");
175         buffer.append("   </Header>\n");
176     }
177 
178     @Override
179     public void BuilderBody(Map<String, Collection<ExportDataModel>> bodyData) {
180         // TODO Auto-generated method stub
181         buffer.append("   <Body>\n");
182         for(String tblname:bodyData.keySet()){
183             buffer.append("   <Dates TableName = \""+tblname+"\">\n");
184             for(ExportDataModel edm:bodyData.get(tblname)){
185                 buffer.append("   <Date>\n");
186                 buffer.append("       <ProductID> "+edm.getProductID()+"</ProductID>\n");
187                 buffer.append("       <Price> "+edm.getPrice()+"</Price>\n");
188                 buffer.append("       <Amount> "+edm.getAmount()+"</Amount>\n");
189             }
190         }
191         buffer.append("   <Body>\n");
192     }
193 
194     @Override
195     public void builderFooter(ExportFooterModel efm) {
196         // TODO Auto-generated method stub
197         buffer.append("    <Footer>\n");
198         buffer.append("        <User>"+efm.getExportUser()+"</User>\n");
199         buffer.append("    </Footer>\n");
200         buffer.append("</Report>\n");
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 文件:\n"+xml.getResult());
268     }
269     
270     
271 }

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

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

 分析建造者\生成器模式

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

 

posted @ 2019-04-29 22:45  彭卫强  阅读(396)  评论(0编辑  收藏  举报
本文原创,文中若有表述不清或存在问题,欢迎指正。共同学习