考慮這樣一種業務場景,咱們構建一個業務對象,可是這個業務對象及其複雜。爲了代碼的根號的可讀性,咱們會把這個對象的構建過程根據精密聯繫的程度來拆分紅幾個類來完成。最後再放到一塊兒使用來生成複雜對象。這個業務場景很是常見,接下來就分析一下解決這個問題更靈活的方式,即:建造者模式。算法
將一個複雜對象的建立與它的表示分離,使得一樣的建立過程能夠建立不一樣的表示。app
看到這個定義之後,確定有不少讀者會有疑問,【複雜對象的建立】的建立好理解,可是【它(複雜對象)的表示】是什麼意思呢,這裏爲了解決讀者可能出現猴急的心情,先大概解釋一下。首先看建造者模式的結構圖ide
Builder:生成器接口,定義建立一個產品所須要的的各個部分的操做。ui
ConcreateBuilder:具體的生成器實現,這個產品在組裝過程當中各個部分所須要的共同的操做。而且還提供一個供用戶獲取組裝完產品的對象。this
Director:指導者,主要用來使用 builder 接口,以一個統一的過程來構建所須要的 Product 對象spa
Product:產品,表示被生成器構建的複雜對象,包含多個部件。code
接下來講下個人理解。建造者模式在建立類似的複雜對象使用,其中 Builder 定義建立這個複雜對象的過程,把建立過程分爲不一樣的部分,也能夠說是不一樣的組成部分。而 ConcreateBuilder 則是對複雜對象建立每部分共同的部分實現出來。xml
類似複雜對象的每步驟類似部分在 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 ,即產品的組裝過程。這樣產品就是很靈活的擴展性,而且產品的表示和組建過程解耦。blog
進而分析出建造者模式的本事是區分 複雜對象的建立 和 它的表示 。這兩個在代碼中的體現是 Director 和 XmlBuilder TxtBuilder。
建造者模式應用場景:能夠靈活的、易擴展的建立複雜對象。而解決的辦法就是分離構建算法和具體構造實現。這樣在擴展的時候能夠根據須要切換 構建算法(Director )和 具體構造實現 (Builder)。只要抓住了這點,基本就理解了生成器的本質了。