2.2-创建和销毁对象-当构造参数太多时考虑使用builder模式

Item 2:当构造参数太多时考虑使用builder模式

可伸缩构造模式

telescoping constructor pattern

这种模式中,包含了多个构造方法,这些构造方法是可选参数的组合。

可伸缩构造模式缺点

  • 难以调用
  • 难以阅读

JavaBeans 模式

无参构造 + setter方法。

JavaBeans 模式缺点

构造方法在多次调用中被分割,所以在构造过程中JavaBean可能处于不一致的状态。

该类没有通过检查构造参数的有效性来执行一致性的选项。在不一致的状态下尝试使用对象可能会导致与包含bug的代码大相径庭的错误,因此很难调试。

变体

当它的构造完成时,手动“冻结”对象,并且不允许它在解冻之前使用,可以减少这些缺点,但是这种变体在实践中很难使用并且很少使用。 而且,在运行时会导致错误,因为编译器无法确保程序员在使用对象之前调用freeze方法。

Builder 模式

结合了可伸缩构造模式的安全性和javabean模式的可读性。

客户端不直接调用所需的对象,而是调用构造方法(或静态工厂),并使用所有必需的参数,并获得一个builder对象。然后,客户端调用builder对象的setter相似方法来设置每个可选参数。最后,客户端调用一个无参的build方法来生成对象,该对象通常是不可变的。Builder通常是它所构建的类的一个静态成员类。

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
// Builder Pattern

public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;

public static class Builder {
// Required parameters
private final int servingSize;
private final int servings;

// Optional parameters - initialized to default values
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0;

public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}

public Builder calories(int val) {
calories = val;
return this;
}

public Builder fat(int val) {
fat = val;
return this;
}

public Builder sodium(int val) {
sodium = val;
return this;
}

public Builder carbohydrate(int val) {
carbohydrate = val;
return this;
}

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

private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
}

使用:

1
2
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
.calories(100).sodium(35).carbohydrate(27).build();

缺点

  • 创建builder对象有成本。
  • 相比于可伸缩构造更冗余。

使用场景

在有大量可选参数相同类型参数时使用。

-------------本文结束感谢您的阅读-------------
0%