建造者模式(BuilderPattern)

简单解读

先看具体代码在来了解这个比较好一些。

构造者模式有四个基本属性:

  1. 具体的产品类

这个类中有可能存在很多复杂的对象,那就很适合用构建者模式。不过实现一中的例子是一个十分简单的构造模式,成员变量全部都为字符串。

  1. 抽象构建者

规范这个产品怎么组建,提供一系列抽象方法,或者用接口。假如将你具体产品类中复杂的那些成员变量都想象成各个零件的话,那这个抽象构建者实际上就是定义怎么生产这些零件,具体生产交由具体的构造者来,生产什么是由导演类来确定的。(具体产品类中那些复杂的对象举个例子来说吧,假如存在一个List,你能知道用的是哪个List的实现类吗?不知道明白我的意思吗,具体的生产什么是看具体的导演类让你生产ArraryList还是其它实现List接口的类。根据导演类给你传输的不同得到的最终对象也就有所差别)

  1. 具体的构建者

实现抽象构建者的所有方法,并且返回一个构建的产品类。

  1. 导演类

导演类是将产品类中的成员变量传输给抽象的建造者,他是和抽象的建造者打交道的。

举个例子来说明:

假如开发一个软件,产品经理(导演类)告诉项目组开发负责人(抽象建造者)的用户需求(告诉用户需求的意思就好比传ArrayList还是其它),然后负责人定制一系列开发计划,当然自己并不去实现 ,就像架构师搭建一个壳子,具体的内容交由普通程序员(具体的构建者)来构建,构建完成后交付给产品经理。

实现一

场景

构造一把M4A1步枪

这个实现一是强行用建造者模式,Rifle这个类中成员变量非常简单,不涉及多态,直接工厂也就就行了。但是为了简化建造者模式更容易理解,才这样写,后续我会模拟一个复杂一点的场景并结合工厂模式说明。

具体产品

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class Rifle {
// 步枪名称
private String name;
// 步枪子弹
private String bullet;
// 枪身
private String gunBody;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getBullet() {
return bullet;
}

public void setBullet(String bullet) {
this.bullet = bullet;
}

public String getGunBody() {
return gunBody;
}

public void setGunBody(String gunBody) {
this.gunBody = gunBody;
}

@Override
public String toString() {
return "Rifle{" +
"name='" + name + '\'' +
", bullet='" + bullet + '\'' +
", gunBody='" + gunBody + '\'' +
'}';
}
}

抽象构造者

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface AbstractRifleBuilder {
// 设置枪的名字
void setName(String name);

// 设置枪身
void setBullet(String bullet);

// 设置子弹
void setGunBody(String gunBody);

// 组装获得步枪
Rifle createRifle();
}

具体构造者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class M4A1Builder implements AbstractRifleBuilder {
private Rifle rifle = new Rifle();

@Override
public void setName(String name) {
rifle.setName(name);
}

@Override
public void setBullet(String bullet) {
rifle.setBullet(bullet);
}

@Override
public void setGunBody(String gunBody) {
rifle.setGunBody(gunBody);
}

@Override
public Rifle createRifle() {
return this.rifle;
}
}

管理者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Director {
private AbstractRifleBuilder rifleBuilder;

public Director(AbstractRifleBuilder rifleBuilder) {
this.rifleBuilder = rifleBuilder;
}

public Rifle createRifle(String name, String bullet, String gunBody) {
this.rifleBuilder.setName(name);
this.rifleBuilder.setBullet(bullet);
this.rifleBuilder.setGunBody(gunBody);
return this.rifleBuilder.createRifle();
}
}

测试方法

1
2
3
4
5
6
7
public class Test {
public static void main(String[] args) {
Director m4A1Director = new Director(new M4A1Builder());
Rifle M4A1 = m4A1Director.createRifle("步枪名称:M4A1", "装填5.56mm子弹", "组装M4A1外壳");
System.out.println(M4A1);
}
}

Rifle{name=’步枪名称:M4A1’, bullet=’装填5.56mm子弹’, gunBody=’组装M4A1外壳’}

小结

上面的那个例子我感觉是最简单的一种构造者模式了,产品类中全是字符串类型的,而且只有一个具体构造者,这也就是一个基本的构造者模式 。

实现二

实现一中的抽象构造者和管理者这两个角色不是必须的。实现二中也可以满足实现一的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
public class Refile {
// 步枪名称
private String name;
// 步枪子弹
private String bullet;
// 枪身
private String gunBody;
// 枪托(可以省略)
private String gunStock;
// 瞄准镜(可以省略)
private String gunSight;

public Refile(RefileBuilder refileBuilder) {
this.name = refileBuilder.name;
this.bullet = refileBuilder.bullet;
this.gunBody = refileBuilder.gunBody;
this.gunStock = refileBuilder.gunStock;
this.gunSight = refileBuilder.gunSight;
}

@Override
public String toString() {
return "Refile{" +
"name='" + name + '\'' +
", bullet='" + bullet + '\'' +
", gunBody='" + gunBody + '\'' +
", gunStock='" + gunStock + '\'' +
", gunSight='" + gunSight + '\'' +
'}';
}

public static class RefileBuilder {
// 步枪名称
private String name;
// 步枪子弹
private String bullet;
// 枪身
private String gunBody;
// 枪托(可以省略)
private String gunStock;
// 瞄准镜(可以省略)
private String gunSight;

public RefileBuilder(String name, String bullet, String gunBody) {
this.name = name;
this.bullet = bullet;
this.gunBody = gunBody;
}

public RefileBuilder setName(String name) {
this.name = name;
return this;
}

public RefileBuilder setBullet(String bullet) {
this.bullet = bullet;
return this;
}

public RefileBuilder setGunBody(String gunBody) {
this.gunBody = gunBody;
return this;
}

public RefileBuilder setGunStock(String gunStock) {
this.gunStock = gunStock;
return this;
}

public RefileBuilder setGunSight(String gunSight) {
this.gunSight = gunSight;
return this;
}

public Refile builder() {
return new Refile(this);
}
}
}

小结

RefileBuilder是Refile的一个静态内部类,这种构造方法适合那些成员变量特别多,而且有成员变量的必须要传过来,有的则无需必须存在,就是这个Refile不用定义非常多的不同参数的构造方法了。定义一个构造方法,可以自主选择set。

个人理解

我感觉这个建造者模式就是将一个对象的所有成员变量的set方法交由别的类(抽象构建者)来管理,交给别的类来构建你这个对象,用户只需将构建这个对象的原材料给说明,对象set方法的管理者就给你将这个对象构建出来并且返回给用户。

工厂方法vs建造者方法

可以看我之前写的工厂方法构造M4A1和这个差不多,看看两者的区别。

工厂方法这个模式就生产M4A1来说,它是直接生产出这个M4A1整体,建造者模式是关注的是这个M4A1的构造过程,枪身,子弹。。组装在一起。工厂方法模式创建对象的粒度比较粗,而建造者模式更加关注这个对象一步一步的创建过程,我感觉这个实际应用中要是十分关注一个对象的过程就使用建造者模式,只关注生产出来某个对象就行那就工厂方法模式。