Effective Java 的笔记,代码、英语原文为主,批注、翻译为辅。
Item 2: Consider a builder when faced with many constructor parameters
当构造函数有多个参数时,考虑使用builder模式
1. Telescoping constructor pattern - does not scale well!
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
|
// Telescoping constructor pattern - does not scale well!
public class NutritionFacts {
private final int servingSize; // (mL) required
private final int servings; // (per container) required
private final int calories; // (per serving) optional
private final int fat; // (g/serving) optional
private final int sodium; // (mg/serving) optional
private final int carbohydrate; // (g/serving) optional
public NutritionFacts(int servingSize, int servings) {
this(servingSize, servings, 0);
}
public NutritionFacts(int servingSize, int servings,
int calories) {
this(servingSize, servings, calories, 0);
}
public NutritionFacts(int servingSize, int servings,
int calories, int fat) {
this(servingSize, servings, calories, fat, 0);
}
public NutritionFacts(int servingSize, int servings,
int calories, int fat, int sodium) {
this(servingSize, servings, calories, fat, sodium, 0);
}
public NutritionFacts(int servingSize, int servings,
int calories, int fat, int sodium, int carbohydrate) {
this.servingSize = servingSize;
this.servings = servings;
this.calories = calories;
this.fat = fat;
this.sodium = sodium;
this.carbohydrate = carbohydrate;
}
public static void main(String[] args) {
NutritionFacts cocaCola =
new NutritionFacts(240, 8, 100, 0, 35, 27);
}
}
|
重叠构造器方法:当有很多参数的时候,客户端代码会
没记错的话我之前做的项目中写的代码就是这样的,使用了大量不同参数的构造方法😅。
2. JavaBeans Pattern - allows inconsistency, mandates mutability
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
|
// JavaBeans Pattern - allows inconsistency, mandates mutability
public class NutritionFacts {
// Parameters initialized to default values (if any)
private int servingSize = -1; // Required; no default value
private int servings = -1; // Required; no default value
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0;
public NutritionFacts() { }
// Setters
public void setServingSize(int val) { servingSize = val; }
public void setServings(int val) { servings = val; }
public void setCalories(int val) { calories = val; }
public void setFat(int val) { fat = val; }
public void setSodium(int val) { sodium = val; }
public void setCarbohydrate(int val) { carbohydrate = val; }
public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);
}
}
|
缺点:
Because construction is split across multiple calls, a JavaBean may be in an inconsistent
state partway through its construction.
构造过程中, JavaBean可能处于不一致
的状态。
A related disadvantage is that the JavaBeans pattern precludes the possibility of making a class immutable and requires added effort on the part of the programmer to ensure thread safety.
JavaBeans 模式会使类可变,导致线程不安全的情况。
没记错的话我之前做的项目中也写过这样的代码,使用了大量setter方法😅。
3. Builder Pattern
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
|
// 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;
}
public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
.calories(100).sodium(35).carbohydrate(27).build();
}
}
|
建造者(Builder)模式
1、优点:
- 保证像重叠构造器模式一样的安全性
- 保证像JavaBeans模式一样的可读性
2、步骤:
Instead of making the desired object directly, the client calls a constructor (or static factory) with all of the required parameters and gets a builder object
. Then the client calls setter-like methods on the builder object to set each optional parameter of interest. Finally, the client calls a parameterless build method
to generate the object, which is typically immutable
.
- 客户端使用所有必需的参数(the required parameters)调用构造函数/静态工厂,得到一个 builder 对象
- 客户端在builder对象上调用类似于 setter 的方法来设置每个相关的可选参数(each optional parameter of interest)
- 客户端调用无参的build方法来生成对象(通常是不可变的)。
3、注意点:
NutritionFacts
不可变。
public static class Builder
Builder是类NutritionFacts的静态成员类。
Summary
In summary, the Builder pattern is a good choice when designing classes whose constructors or static factories would have more than a handful of parameters, especially if many of the parameters are optional or of identical type
. Client code is much easier to read and write with builders than with telescoping constructors, and builders are much safer than JavaBeans.
所以既然学习了Builder模式,在编码的时候应该灵活使用,而不是再写之前蹩脚的代码了。
设计模式果然是有实际应用的,自己学这门课程的时候,感觉例子枯燥,也没有实际应用。果然还是要看书看书📚,使用设计模式编码设计好的代码。
Author
Anjana
LastMod
2022-03-21
License
原创文章,如需转载请注明作者和出处。谢谢!