设计模式学习-建造者模式

1.定义

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

2.类图

3.代码示例

 1 package com.zhaoyangwoo.builder;
 2 
 3 /**
 4  * Created by john on 16/5/7.
 5  * 场景类
 6  */
 7 public class Builder {
 8 
 9     public static void Main(){
10         BuilderInterface bi = new ConceptBuilder();
11         Director director = new Director();
12         director.construct(bi);
13     }
14 
15 }
16 
17 /**
18  * 导演类
19  */
20 class Director {
21     Product construct(BuilderInterface bi){
22         bi.setProductPartA();
23         bi.setProductPartB();
24         return bi.getProduct();
25     }
26 }
27 
28 /**
29  * 抽象建造者
30  */
31 interface BuilderInterface{
32     void setProductPartA();
33     void setProductPartB();
34     Product getProduct();
35 }
36 
37 /**
38  * 具体建造者
39  */
40 class ConceptBuilder implements BuilderInterface{
41 
42     private Product product = new Product();
43 
44     @Override
45     public void setProductPartA() {
46         product.setName("产品A");
47     }
48 
49     @Override
50     public void setProductPartB() {
51         product.setPrice(1.111);
52     }
53 
54     @Override
55     public Product getProduct() {
56         return product;
57     }
58 }
59 
60 
61 /**
62  * 具体产品
63  */
64 class Product{
65     public String getName() {
66         return name;
67     }
68 
69     public void setName(String name) {
70         this.name = name;
71     }
72 
73     String name;
74 
75     public double getPrice() {
76         return price;
77     }
78 
79     public void setPrice(double price) {
80         this.price = price;
81     }
82 
83     double price;
84 }

4.应用场景举例

  • 创建更复杂对象,隔离对象创建的具体过程 

5.JDK源码中的模式实现

  Calendar.Builder静态类就是典型的建造者模式,我们来看源码  

 1 public Calendar build() {
 2             if (locale == null) {
 3                 locale = Locale.getDefault();
 4             }
 5             if (zone == null) {
 6                 zone = TimeZone.getDefault();
 7             }
 8             Calendar cal;
 9             if (type == null) {
10                 type = locale.getUnicodeLocaleType("ca");
11             }
12             if (type == null) {
13                 if (locale.getCountry() == "TH"
14                     && locale.getLanguage() == "th") {
15                     type = "buddhist";
16                 } else {
17                     type = "gregory";
18                 }
19             }
20             switch (type) {
21             case "gregory":
22                 cal = new GregorianCalendar(zone, locale, true);
23                 break;
24             case "iso8601":
25                 GregorianCalendar gcal = new GregorianCalendar(zone, locale, true);
26                 // make gcal a proleptic Gregorian
27                 gcal.setGregorianChange(new Date(Long.MIN_VALUE));
28                 // and week definition to be compatible with ISO 8601
29                 setWeekDefinition(MONDAY, 4);
30                 cal = gcal;
31                 break;
32             case "buddhist":
33                 cal = new BuddhistCalendar(zone, locale);
34                 cal.clear();
35                 break;
36             case "japanese":
37                 cal = new JapaneseImperialCalendar(zone, locale, true);
38                 break;
39             default:
40                 throw new IllegalArgumentException("unknown calendar type: " + type);
41             }
42             cal.setLenient(lenient);
43             if (firstDayOfWeek != 0) {
44                 cal.setFirstDayOfWeek(firstDayOfWeek);
45                 cal.setMinimalDaysInFirstWeek(minimalDaysInFirstWeek);
46             }
47             if (isInstantSet()) {
48                 cal.setTimeInMillis(instant);
49                 cal.complete();
50                 return cal;
51             }
52 
53             if (fields != null) {
54                 boolean weekDate = isSet(WEEK_YEAR)
55                                        && fields[WEEK_YEAR] > fields[YEAR];
56                 if (weekDate && !cal.isWeekDateSupported()) {
57                     throw new IllegalArgumentException("week date is unsupported by " + type);
58                 }
59 
60                 // Set the fields from the min stamp to the max stamp so that
61                 // the fields resolution works in the Calendar.
62                 for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
63                     for (int index = 0; index <= maxFieldIndex; index++) {
64                         if (fields[index] == stamp) {
65                             cal.set(index, fields[NFIELDS + index]);
66                             break;
67                         }
68                     }
69                 }
70 
71                 if (weekDate) {
72                     int weekOfYear = isSet(WEEK_OF_YEAR) ? fields[NFIELDS + WEEK_OF_YEAR] : 1;
73                     int dayOfWeek = isSet(DAY_OF_WEEK)
74                                     ? fields[NFIELDS + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
75                     cal.setWeekDate(fields[NFIELDS + WEEK_YEAR], weekOfYear, dayOfWeek);
76                 }
77                 cal.complete();
78             }
79 
80             return cal;
81         }
View Code

  另外StringBuilder也同样是建造者模式的典型应用

6.思考

  • 建造者模式和工厂模式
   两者非常相似,把握异同的关键点在于:建造者关注的是基本方法(零件)的组装顺序,所有基本操作都已经实现。而工厂模式关注的是零件的创建。
  

   


  • 建造者模式和模版方法模式

    1.这两个模式解决问题的类型不一样,建造者模式是创建对象,模版方法是将实现推迟到子类中

     2.如果建造者模式省掉导演类,那么builder构建方法就应该是模版方法

7.参考

  1.模板方法模式VS建造者模式

  2.建造者模式

原文地址:https://www.cnblogs.com/zhaoyanghoo/p/5463775.html