1. 什么是建造者模式
  2. 解决了什么问题
  3. 使用场景
  4. 常见的实现场景
  5. 场景案例
  6. 使用流行的建造者模式解决问题
  7. 不适用建造者模式解决问题
  8. 使用传统的建造者模式解决问题

什么是建造者模式

隐藏了复杂对象的创建过程,它把复杂对象的创建过程加以抽象,通过子类继承或者重载的方式,动态的创建具有复合属性的对象。

解决了什么问题

该模式解决的是如何将一个复杂对象(属性多)赋值的问题

使用场景

大家想想,平时如何一个对象赋值?

1、构造器

平时常用的方式,虽然构造器用起来很方便,但随着属性增多,那么需要写的构造器也会增多多,而且容易传混

2、set方式

缺点:对象状态易发生变化,也是一长串,实现起来不美观

常用的实现场景

①lombok中的@Builder注解

比如刚才House对象

1
2
3
4
5
6
@Builder
public class House {
private String base;
private String wall;
private String cell;
}

在编译后(与我们手动实现的相似)

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
public class House {
private String base;
private String wall;
private String cell;
House(String base, String wall, String cell) {
this.base = base;
this.wall = wall;
this.cell = cell;
}
public static House.HouseBuilder builder() {
return new House.HouseBuilder();
}

public static class HouseBuilder {
private String base;
private String wall;
private String cell;
HouseBuilder() {}

public House.HouseBuilder base(String base) {
this.base = base;
return this;
}
public House.HouseBuilder wall(String wall) {
this.wall = wall;
return this;
}
public House.HouseBuilder cell(String cell) {
this.cell = cell;
return this;
}
public House build() {
return new House(this.base, this.wall, this.cell);
}
//toString
}
}

②StringBuilder类,相信大部分人都使用过

1
2
3
4
StringBuilder builder = new StringBuilder();
builder.append(1)
.append(2)
.append(3);

源码中也是采用return this的方式实现

1
2
3
4
5
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}

img

append()的方法由接口Appendable定义(该接口类似抽象建造者)

由抽象类AbstractStringBuilder实现该接口 (该抽象类 类似具体建造者,但不能实例化)

最后给StringBuilder去调用append方法 (类似指挥者/调用方)

这样的话与上方的设计模式不同了,这个就是境界,只能说写JDK源码的大佬在第五层

建造者模式,实现的方式有两种

①流行的实现方式—链式编程

通过在对象中添加静态类的方式去创建对象

假设我需要建造一个房子,给房子的一些属性赋值

房子类

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
public class House {
//地基
private String base;
//墙
private String wall;
//吊顶
private String cell;
//构造器
public House(Builder builder) {
this.base = builder.base;
this.wall = builder.wall;
this.cell = builder.cell;
}

public static class Builder{
//地基
private String base;
//墙
private String wall;
//吊顶
private String cell;
//set
public Builder base(String base) {
this.base = base;
return this;
}
public Builder wall(String wall) {
this.wall = wall;
return this;
}
public Builder cell(String cell) {
this.cell = cell;
return this;
}
public House build(){
return new House(this);
}
}
//toString方法忽略
}

调用方式

1
2
3
4
5
House house = new House.Builder()
.base("流行房子的地基")
.wall("流行方式的墙")
.cell("流行方式的顶子")
.build();

这种方式就一个类,调用起来也美观,线程安全,强烈推荐

②传统的建造者模式

也是经典的build模式,网上一搜一大把,看着高大上,但不实用,感兴趣可以看看

如果不适用建造者模式,我们怎么进行对象赋值?

传统的建造者模式又怎么赋值?下面是代码对比

1
2
3
4
5
6
7
8
9
10
//普通方式盖房子
House house1 = new House();
house1.setBase("普通房子的地基");
house1.setWall("普通房子的墙");
house1.setCell("普通房子的吊顶");
System.out.println(house1);
//建造者模式盖房子(Director相当于client)
Director director = new Director();
House house = director.build(new FiveBuilder());
System.out.println(house);

优势在于不论多少个属性赋值,都是一句话去创建,值在具体建造者中已设置,后面说

角色

产品,产品对象,抽象建造者,具体建造者

相当于一个对象需要4个类,而仅仅是为了解耦,没感觉到好处

UML类图

img

可以看到调用方(Director)确实与产品(House)进行了解耦,应该也是唯一的好处了

代码实现

房子类

1
2
3
4
5
6
7
8
9
10
public class House {
//地基
private String base;
//墙
private String wall;
//吊顶
private String cell;

//set get toString方法省略
}

抽象建造者类

1
2
3
4
5
6
7
8
9
10
public interface HouseBuilder {
//地基赋值
HouseBuilder buildBase();
//墙赋值
HouseBuilder buildWall();
//吊顶赋值
HouseBuilder buildCell();
//获得房子
House getHouse();
}

具体建造者

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 FiveBuilder implements HouseBuilder {
//这个建造者给房子赋的值
private String base = "五角大楼的地基";
private String wall = "五角大楼的墙";
private String cell = "五角大楼的吊顶";
private House house;

public FiveBuilder() {
house = new House();
}

@Override
public HouseBuilder buildBase() {
house.setBase(base);
return this;
}

@Override
public HouseBuilder buildWall() {
house.setWall(wall);
return this;
}

@Override
public HouseBuilder buildCell() {
house.setCell(cell);
return this;
}

@Override
public House getHouse() {
return house;
}
}

指挥者/客户端(调用方)

1
2
3
4
5
6
7
8
9
public class Director {
//根据给定的建造者建造不同的房子
public House build(HouseBuilder builder) {
builder.buildBase()
.buildWall()
.buildCell();
return builder.getHouse();
}
}

其中的解耦思想可以借鉴,也属于面向接口编程

总结

设计模式学的终归是一种思想,不必生搬硬套,也不用死记UML类图,重要的是体会每个设计模式的思想,并通过大量的业务来累积经验,来不断证明设计模式的好处