建造者模式小记

前言

当一个类的属性足够多时,且不确定在构造对象时,哪些属性必须,哪些是非必须的。此时,创建该对象这件事情变的不确定。我们也许要排列组合般的写上无数个构造函数,这样显得十分臃肿。此时,一个较为优雅的设计模式应运而生—建造者模式(Builder Pattern)

传统形式

传统的建造者模式由四大部分组成:Product(最终要生成的对象)、Builder(创建着的抽象基类)、ConcreteBuilder(Builder实现类,负责干活)、Director(调用类)

代码示例:

下面是一个Product电脑类,由必须部分和非必须部分组成

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
@Data
public class Computer {

/**
* 必须
*/
private String cpu;

/**
* 必须
*/
private String gpu;

/**
* 非必须
*/
private String os;

/**
* 非必须
*/
private String keyboard;

/**
* 非必须
*/
private String display;

public Computer(String cpu, String gpu) {
this.cpu = cpu;
this.gpu = gpu;
}

}

定义一个抽象的Builder:

1
2
3
4
5
6
7
8
9
public interface Builder<T> {

/**
* 构建行为的抽象
* @return
*/
T build();

}

定义两个不通品牌电脑的实现:

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
public class WindowsComputerBuilder implements Builder<Computer> {

private Computer computer;

public WindowsComputerBuilder builder(String cpu, String gpu) {
this.computer = new Computer(cpu, gpu);
return this;
}

public WindowsComputerBuilder os(String os) {
computer.setOs(os);
return this;
}

public WindowsComputerBuilder keyboard(String keyboard) {
computer.setKeyboard(keyboard);
return this;
}

public WindowsComputerBuilder display(String display) {
computer.setDisplay(display);
return this;
}

@Override
public Computer build() {
return computer;
}
}
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
public class MacComputerBuilder implements Builder<Computer> {

private Computer computer;

public MacComputerBuilder builder(String cpu, String gpu) {
this.computer = new Computer(cpu, gpu);
return this;
}

public MacComputerBuilder os(String os) {
computer.setOs(os);
return this;
}

public MacComputerBuilder keyboard(String keyboard) {
computer.setKeyboard(keyboard);
return this;
}

public MacComputerBuilder display(String display) {
computer.setDisplay(display);
return this;
}

@Override
public Computer build() {
return computer;
}

}

Director生产两种不同的电脑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Director {

public static void main(String[] args) {

// 建造一个windows电脑
Computer windows = new WindowsComputerBuilder().builder("intel", "rtx")
.os("windows")
.keyboard("windows键盘")
.display("windows显示器").build();
System.out.println(windows);
// 建造一个mac电脑
Computer macbook = new MacComputerBuilder().builder("m2", "intel hd")
.os("macos")
.keyboard("mac键盘")
.display("mac显示器").build();
System.out.println(macbook);

}

}

可以看到,Builder Pattern生成对象时一般都会执行链式调用,且区分除了必须和非必须的参数

1
2
Computer(cpu=intel, gpu=rtx, os=windows, keyboard=键盘, display=显示器)
Computer(cpu=m2, gpu=intel hd, os=macos, keyboard=键盘, display=显示器)

这样做,构建对象时显得更为优雅

JAVA中简化方式

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
@Data
public class Computer {

/**
* 必须
*/
private String cpu;

/**
* 必须
*/
private String gpu;

/**
* 非必须
*/
private String os;

/**
* 非必须
*/
private String keyboard;

/**
* 非必须
*/
private String display;

public Computer(Builder builder) {
this.cpu = builder.cpu;
this.gpu = builder.gpu;
this.os = builder.os;
this.keyboard = builder.keyboard;
this.display = builder.display;
}

public static class Builder{

private String cpu;
private String gpu;
private String os;
private String keyboard;
private String display;

public Builder(String cpu, String gpu) {
this.cpu = cpu;
this.gpu = gpu;
}

public Builder os(String os) {
this.os = os;
return this;
}

public Builder keyboard(String keyboard) {
this.keyboard = keyboard;
return this;
}

public Builder display(String display) {
this.display = display;
return this;
}

public Computer build() {
return new Computer(this);
}

}

}

将构建者成为了该类的一个静态内部类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Director {

public static void main(String[] args) {

// 建造一个windows电脑
Computer windows = new Computer.Builder("intel", "rtx")
.os("windows")
.keyboard("windows键盘")
.display("windows显示器").build();
System.out.println(windows);
// 建造一个mac电脑
Computer macbook = new Computer.Builder("m2", "intel hd")
.os("macos")
.keyboard("mac键盘")
.display("mac显示器").build();
System.out.println(macbook);

}

}

调用结果:

1
2
Computer(cpu=intel, gpu=rtx, os=windows, keyboard=windows键盘, display=windows显示器)
Computer(cpu=m2, gpu=intel hd, os=macos, keyboard=mac键盘, display=mac显示器)

使用工具

lombok该SDK提供了@Builder注解,可以一键构建对象