设计模式之建造者模式

建造者模式

建造者模式

建造者模式(Builder Pattern)是将一个复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建不同的表示,属于创建型模式。使用建造者模式对于用户而言只需指定需要建造的类型就可以获得对象,建造过程及细节不需要了解。

建造者模式适用于创建对象需要很多步骤,但是步骤的顺序不一定固定。如果一个对象有非常复杂的内部结构(很多属性),可以将复杂对象的创建和使用进行分离。

应用场景

建造者模式适用于一个具有较多的零件的复杂产品的创建过程,由于需求的变化,组成这个复杂产品的各个零件经常猛烈变化,但是它们的组合方式却相对稳定。

建造者模式适用于以下几种场景:

1、相同的方法,不同的执行顺序,产生不同的结果时。

2、多个部件或零件,都可以装配到一个对象中,但是产生的结果又不相同。

3、产品类非常复杂,或者产品类中的调用顺序不同产生不同的作用。

4、当初始化一个对象特别复杂,参数多,而且很多参数都具有默认值时。

基本写法

以课程为例,一个完整的课程需要由PPT课件、回放视频、课堂笔记、课后作业组成,但是这些内容的设置顺序可以随意调整,用建造者模式来代入理解一下。首先创建一个需要构造的产品类Course:

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
public class Course
{
private String name;
private String ppt;
private String video;
private String note;
private String homework;

public String getName()
{
return name;
}

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

public String getPpt()
{
return ppt;
}

public void setPpt(String ppt)
{
this.ppt = ppt;
}

public String getVideo()
{
return video;
}

public void setVideo(String video)
{
this.video = video;
}

public String getNote()
{
return note;
}

public void setNote(String note)
{
this.note = note;
}

public String getHomework()
{
return homework;
}

public void setHomework(String homework)
{
this.homework = homework;
}

@Override
public String toString()
{
return "Course{" + "name='" + name + '\'' + ", ppt='" + ppt + '\'' + ", video='" + video + '\'' + ", note='"
+ note + '\'' + ", homework='" + homework + '\'' + '}';
}
}

然后创建建造者类CourseBuider,将复杂的构造过程封装起来,构造步骤由用户决定:

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
public class CourseBuilder
{
private Course course = new Course();

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

public void addPpt(String ppt)
{
this.course.setPpt(ppt);
}

public void addVideo(String video)
{
this.course.setVideo(video);
}

public void addNote(String note)
{
this.course.setNote(note);
}

public void addHomework(String homework)
{
this.course.setHomework(homework);
}

public Course build()
{
return course;
}
}

测试类

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args)
{
CourseBuilder builder = new CourseBuilder();
builder.addName("设计模式");
builder.addPpt("【PPT课件】");
builder.addVideo("【回放视频】");
builder.addNote("【课堂笔记】");
builder.addHomework("【课后作业】");
System.out.println(builder.build());
}

链式写法

在平时的应用中,建造者模式通常是采用链式编程的方式构造对象,修改CourseBuilder类,将CourseBuilder变为Course的内部类:

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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
public class Course
{
private String name;
private String ppt;
private String video;
private String note;
private String homework;

public String getName()
{
return name;
}

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

public String getPpt()
{
return ppt;
}

public void setPpt(String ppt)
{
this.ppt = ppt;
}

public String getVideo()
{
return video;
}

public void setVideo(String video)
{
this.video = video;
}

public String getNote()
{
return note;
}

public void setNote(String note)
{
this.note = note;
}

public String getHomework()
{
return homework;
}

public void setHomework(String homework)
{
this.homework = homework;
}

@Override
public String toString()
{
return "Course{" + "name='" + name + '\'' + ", ppt='" + ppt + '\'' + ", video='" + video + '\'' + ", note='"
+ note + '\'' + ", homework='" + homework + '\'' + '}';
}

public static class CourseBuilder
{
private Course course = new Course();

public CourseBuilder addName(String name)
{
this.course.setName(name);
return this;
}

public CourseBuilder addPpt(String ppt)
{
this.course.setPpt(ppt);
return this;
}

public CourseBuilder addVideo(String video)
{
this.course.setVideo(video);
return this;
}

public CourseBuilder addNote(String note)
{
this.course.setNote(note);
return this;
}

public CourseBuilder addHomework(String homework)
{
this.course.setHomework(homework);
return this;
}

public Course build()
{
return course;
}
}
}

也可将CourseBuilder独立出来

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
 public static void main(String[] args)
{

Course course = new Course.CourseBuilder()
.addName("设计模式")
.addPpt("【PPT课件】")
.addVideo("【回放视频】")
.addNote("【课堂笔记】")
.addHomework("【课后作业】")
.build();
System.out.println(course);

}

建造者模式还可以做更多的事

我们可以把校验逻辑放置到 Builder 类中,先创建建造者,并且通过 set() 方法设置建造者的变量值,然后在使用 build() 方法真正创建对象之前,做集中的校验,校验通过之后才会创建对象。除此之外,我们可以把构造函数改为 private 私有权限。这样我们就只能通过建造者来创建类对象。并且,类没有提供任何 set() 方法,这样我们创建出来的对象就是不可变对象了。

示例代码,使用ResourcePoolConfig示例

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
80
81
82
83

public class ResourcePoolConfig {
private String name;
private int maxTotal;
private int maxIdle;
private int minIdle;

private ResourcePoolConfig(Builder builder) {
this.name = builder.name;
this.maxTotal = builder.maxTotal;
this.maxIdle = builder.maxIdle;
this.minIdle = builder.minIdle;
}
//...省略getter方法...

//我们将Builder类设计成了ResourcePoolConfig的内部类。
//我们也可以将Builder类设计成独立的非内部类ResourcePoolConfigBuilder。
public static class Builder {
private static final int DEFAULT_MAX_TOTAL = 8;
private static final int DEFAULT_MAX_IDLE = 8;
private static final int DEFAULT_MIN_IDLE = 0;

private String name;
private int maxTotal = DEFAULT_MAX_TOTAL;
private int maxIdle = DEFAULT_MAX_IDLE;
private int minIdle = DEFAULT_MIN_IDLE;

public ResourcePoolConfig build() {
// 校验逻辑放到这里来做,包括必填项校验、依赖关系校验、约束条件校验等
if (StringUtils.isBlank(name)) {
throw new IllegalArgumentException("...");
}
if (maxIdle > maxTotal) {
throw new IllegalArgumentException("...");
}
if (minIdle > maxTotal || minIdle > maxIdle) {
throw new IllegalArgumentException("...");
}

return new ResourcePoolConfig(this);
}

public Builder setName(String name) {
if (StringUtils.isBlank(name)) {
throw new IllegalArgumentException("...");
}
this.name = name;
return this;
}

public Builder setMaxTotal(int maxTotal) {
if (maxTotal <= 0) {
throw new IllegalArgumentException("...");
}
this.maxTotal = maxTotal;
return this;
}

public Builder setMaxIdle(int maxIdle) {
if (maxIdle < 0) {
throw new IllegalArgumentException("...");
}
this.maxIdle = maxIdle;
return this;
}

public Builder setMinIdle(int minIdle) {
if (minIdle < 0) {
throw new IllegalArgumentException("...");
}
this.minIdle = minIdle;
return this;
}
}
}

// 这段代码会抛出IllegalArgumentException,因为minIdle>maxIdle
ResourcePoolConfig config = new ResourcePoolConfig.Builder()
.setName("dbconnectionpool")
.setMaxTotal(16)
.setMaxIdle(10)
.setMinIdle(12)
.build();

建造者模式的优缺点

建造者模式的优点:
1、封装性好,创建和使用分离;
2、扩展性好,建造类之间独立、一定程度上解耦。

建造者模式的缺点:
1、产生多余的Builder对象;
2、产品内部发生变化,建造者都要修改,成本较大。

建造者模式和工厂模式的区别

建造者模式和工厂模式有什么区别呢?

1、建造者模式更加注重方法的调用顺序,工厂模式注重于创建对象。
2、创建对象的力度不同,建造者模式创建复杂的对象,由各种复杂的部件组成,工厂模式创建出来的都一样。
3、关注重点不一样,工厂模式模式只需要把对象创建出来就可以了,而建造者模式中不仅要创建出这个对象,还要知道这个对象由哪些部件组成。
4、建造者模式根据建造过程中的顺序不一样,最终的对象部件组成也不一样。

打赏

请我喝杯咖啡吧~

支付宝
微信