建造者模式

建造者模式(Builder),又叫生成器模式,是一种对象构建模式。它将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式可以将一个产品的内部表象和产品的生成过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。如果我们用了建造者模式,那么用户就只需指定需要建造的类型就可以得到它们,而具体建造的过程和细节就不需要知道了。

建造者模式解析

建造者模式结构图

角色介绍

  • Product(产品角色):具体产品对象。
  • Builder(抽象建造者):是为创建一个 Product 对象的各个部件指定的抽象接口。
  • ConcreteBuilder(具体建造者):实现 Builder 接口,构建和装配各个部件。
  • Director(指挥者):是构建一个使用 Builder 接口的对象。它主要是用于创建一个复杂的对象。 它主要有两个作用,一是隔离了客户与对象的生产过程,二是负责控制产品对象的生产过程。

建造者模式基本代码

  • Product 类:产品类,由多个部件组成。
1
public class Product {
2
3
    private List<String> parts = new ArrayList<>();
4
5
    /**
6
     * 添加部件
7
     */
8
    public void add(String part) {
9
        this.parts.add(part);
10
    }
11
12
    /**
13
     * 列举所有部件
14
     */
15
    public void show() {
16
        this.parts.forEach(System.out::println);
17
    }
18
}
  • Builder 类:抽象建造者类,确定产品由两个部件 PartA 和 PartB 组成,并声明一个得到产品结果的方法 getResult()。
1
public interface Builder {
2
3
    void buildPartA();
4
5
    void buildPartB();
6
7
    Product getResult();
8
}
  • ConcreteBuilderA 类:具体建造者 A。
1
public class ConcreteBuilderA implements Builder {
2
3
    private Product product = new Product();
4
5
    @Override
6
    public void buildPartA() {
7
        product.add("X");
8
    }
9
10
    @Override
11
    public void buildPartB() {
12
        product.add("Y");
13
    }
14
15
    @Override
16
    public Product getResult() {
17
        return product;
18
    }
19
}
  • ConcreteBuilderB 类:具体建造者 B。
1
public class ConcreteBuilderB implements Builder {
2
3
    private Product product = new Product();
4
5
    @Override
6
    public void buildPartA() {
7
        product.add("M");
8
    }
9
10
    @Override
11
    public void buildPartB() {
12
       product.add("N");
13
    }
14
15
    @Override
16
    public Product getResult() {
17
        return product;
18
    }
19
}
  • Director 类:指挥者类。
1
public class Director {
2
3
    public void build(Builder builder) {
4
        builder.buildPartA();
5
        builder.buildPartB();
6
    }
7
}
  • Main 类
1
public class Main {
2
3
    public static void main(String[] args) {
4
        Director director = new Director();
5
6
        ConcreteBuilderA builderA = new ConcreteBuilderA();
7
        ConcreteBuilderB builderB = new ConcreteBuilderB();
8
9
        director.build(builderA);
10
        Product resultA = builderA.getResult();
11
        resultA.show();
12
13
        director.build(builderB);
14
        Product resultB = builderB.getResult();
15
        resultB.show();
16
    }
17
}

示例

需求:盖房子,过程有打桩、砌墙、封顶。房子有各种各样的,比如普通房,高楼,别墅,各种房子的过程虽然一样,但是要求不相同的。

传统写法

1
/**
2
 * House
3
 */
4
public class House {
5
6
    private Integer length;
7
8
    private Integer width;
9
10
    private Integer high;
11
12
    public Integer getLength() {
13
        return length;
14
    }
15
16
    public void setLength(Integer length) {
17
        this.length = length;
18
    }
19
20
    public Integer getWidth() {
21
        return width;
22
    }
23
24
    public void setWidth(Integer width) {
25
        this.width = width;
26
    }
27
28
    public Integer getHigh() {
29
        return high;
30
    }
31
32
    public void setHigh(Integer high) {
33
        this.high = high;
34
    }
35
36
    @Override
37
    public String toString() {
38
        return "House{" +
39
                "length=" + length +
40
                ", width=" + width +
41
                ", high=" + high +
42
                '}';
43
    }
44
}
45
46
/**
47
 * 普通房子
48
 */
49
public class CommonHouseBuilder {
50
    
51
    public House build() {
52
        House house = new House();
53
        house.setLength(50);
54
        house.setWidth(20);
55
        house.setHigh(5);
56
57
        return house;
58
    }
59
}
60
61
/**
62
 * 高房子
63
 */
64
public class HighHouseBuilder {
65
66
    public House build() {
67
        House house = new House();
68
        house.setLength(60);
69
        house.setWidth(30);
70
        house.setHigh(6);
71
72
        return house;
73
    }
74
}
75
76
/**
77
 * Main
78
 */
79
public class Main {
80
81
    public static void main(String[] args) {
82
        // 普通房子
83
        CommonHouseBuilder commonHouseBuilder = new CommonHouseBuilder();
84
        House commonHouse = commonHouseBuilder.build();
85
        System.out.println(commonHouse.toString());
86
87
        // 高房子
88
        HighHouseBuilder highHouseBuilder = new HighHouseBuilder();
89
        House highHouse = highHouseBuilder.build();
90
        System.out.println(highHouse.toString());
91
92
    }
93
}

上面这种写法将建造过程和表象都放在了一起,耦合性很强,而且普通房子和高房子的建造过程是一样的,只是内部的细节不同,代码是可以复用的。如果我们又要进行别墅的建造,建造过程我们又要重新写一遍,而且很容易漏写步骤。所以让我们使用建造者模式改进。

使用建造者模式改进

1
/**
2
 * House
3
 */
4
public class House {
5
6
    private Integer length;
7
8
    private Integer width;
9
10
    private Integer high;
11
12
    public Integer getLength() {
13
        return length;
14
    }
15
16
    public void setLength(Integer length) {
17
        this.length = length;
18
    }
19
20
    public Integer getWidth() {
21
        return width;
22
    }
23
24
    public void setWidth(Integer width) {
25
        this.width = width;
26
    }
27
28
    public Integer getHigh() {
29
        return high;
30
    }
31
32
    public void setHigh(Integer high) {
33
        this.high = high;
34
    }
35
36
    @Override
37
    public String toString() {
38
        return "House{" +
39
                "length=" + length +
40
                ", width=" + width +
41
                ", high=" + high +
42
                '}';
43
    }
44
}
45
46
/**
47
 * Builder
48
 */
49
public interface Builder {
50
51
    void buildPartA();
52
53
    void buildPartB();
54
55
    Product getResult();
56
}
57
58
/**
59
 * 普通房子建造者
60
 */
61
public class CommonHouseBuilder implements HouseBuilder {
62
63
    private House house = new House();
64
65
    @Override
66
    public void buildHigh() {
67
        house.setHigh(5);
68
    }
69
70
    @Override
71
    public void buildWidth() {
72
        house.setWidth(20);
73
    }
74
75
    @Override
76
    public void buildLength() {
77
       house.setLength(50);
78
    }
79
80
    @Override
81
    public House getResult() {
82
        return house;
83
    }
84
}
85
86
/**
87
 * 高房子建造者
88
 */
89
public class HighHouseBuilder implements HouseBuilder {
90
91
    private House house = new House();
92
93
    @Override
94
    public void buildHigh() {
95
        house.setHigh(6);
96
    }
97
98
    @Override
99
    public void buildWidth() {
100
        house.setWidth(30);
101
    }
102
103
    @Override
104
    public void buildLength() {
105
        house.setLength(60);
106
    }
107
108
    @Override
109
    public House getResult() {
110
        return house;
111
    }
112
}
113
114
/**
115
 * HouseDirector
116
 */
117
public class HouseDirector {
118
119
    public void buildHouse(HouseBuilder houseBuilder) {
120
        houseBuilder.buildHigh();
121
        houseBuilder.buildLength();
122
        houseBuilder.buildWidth();
123
    }
124
}
125
126
/**
127
 * Main
128
 */
129
public class Main {
130
131
    public static void main(String[] args) {
132
        HouseDirector houseDirector = new HouseDirector();
133
        // 普通房子
134
        CommonHouseBuilder commonHouseBuilder = new CommonHouseBuilder();
135
        houseDirector.buildHouse(commonHouseBuilder);
136
        House commonHouse = commonHouseBuilder.getResult();
137
        System.out.println(commonHouse.toString());
138
139
        // 高房子
140
        HighHouseBuilder highHouseBuilder = new HighHouseBuilder();
141
        houseDirector.buildHouse(highHouseBuilder);
142
        House highHouse = highHouseBuilder.getResult();
143
        System.out.println(highHouse.toString());
144
145
    }
146
}

小结

建造者模式,主要用于创建一些复杂的对象,这些对象内部构建间的建造顺序通常是稳定的,但对象内部的构建通常面临复杂的变化。而建造者模式的好处就是使得建造代码与表示代码分离,由于建造者隐藏了该产品的构建过程,所以如果要改变一个产品内部的表示,只需再定义一个具体的建造者就可以了。

最后,建造者模式是逐步建造产品的,所以建造者的 Builder 类里的那些建造方法必须是足够普遍的,以便为各类型的具体建造者构造。如果产品的差异性较大,就不适合使用建造者模式。