我有4个可以默认初始化的实例变量,下面写的代码合适吗?构造函数的数量正在以惊人的速度增长,我会使用具有 getter 和 setter 的 Builder 对象吗?
class Example {
private int a;
private String s;
private Object object;
private boolean aBoolean;
public Example(int a1, String s1, Object object1, boolean aBoolean1) {
a = a1;
s = s1;
object = object1;
aBoolean = aBoolean1;
}
public Example(int a1, String s1, Object object1) {
this(a1, s1, object1, true);
}
public Example(int a1, String s1) {
this(a1, s1, new Object(), true);
}
public Example(int a1,boolean aBoolean1) {
this(a1, "a String", new Object(), aBoolean1);
}
// ...(for all other combinations)
}
本质上来说,不。作为一个概念,这无法扩展。有两种方式。
假设您有 6 个字段,并且它们都有默认值。这意味着您正在创建 2 到 6 个不同的构造函数(64 个构造函数)。除了表面上看很疯狂而且肯定无法维护这一事实之外,即使您决定使用一些自动化工具或注释处理器来生成它们,由于类文件的限制,您可以拥有的数量也有 65536 个限制。
假设您有 2 个字段(
a
和 b
),并且它们都有默认值。这两个字段的类型都是 int
。你不能这样做 - 仅采用 a
并保留 b
为默认值的构造函数与仅采用 b
并保留 a
为默认值的构造函数冲突 - 两者都具有签名 YourType(int)
。
不要创造组合爆炸,只需继续前进。因此,假设一个类有 3 个字段 (
int a; int b; String c;
),你就有 4 个构造函数:
()
(int a)
(int a, int b)
(int a, int b, String c)
换句话说,如果还提供了“下方”的任何字段,则给定“字段”是必需的。然后以合理的顺序对字段进行排序。这使您拥有的构造函数的数量保持在可管理的范围内(如果它们是默认的 1+n,这与您拥有的字段数量成线性关系,而不是 fac(n) 爆炸)。它或多或少也符合 Java 程序员的期望,并且它与其他各种类似工作的语言相匹配。 只有全和无
懂事
建设者
// given:
class Bridge {
int yearBuilt;
int span;
String name;
}
// do not construct like this:
new Bridge(1937, 1280, "Golden Gate");
你不这样构建的原因不仅仅是,因为它使得让每个参数都是可选的变得非常棘手。另外,调用本身也变得不可读。那是一座建于1937年、最大跨度为1280米的桥,还是一座建于1280年、最大跨度为1937米的桥?如果没有 javadoc 或让我的 IDE 突出显示这些参数的名称,则无法从这个调用中看出。
相反,你让你的图书馆用户写下这个:
Bridge.builder()
.buildYear(1937)
.maxSpan(1280)
.name("Golden Gate")
.build();
这有各种各样的优点:
每个参数都可以是默认/可选的,不会出现
fac(n)
您可以创建多种替代方法来指定给定字段值。也许
.buildDate(LocalDate.of(1937, 4, 19))
.buildDate(1937, Month.APRIL, 19)
——如果你真的想要那样,至少它不会让组合爆炸效果变得更糟。
调用者拥有可读的代码 - 现在只要查看该代码,我就不可能混淆构建年份的跨度。
builder()
、build()
、私有构造函数等等)。
Project Lombok 会为您生成所有这些:
@Builder
文档。即使您不能使用 lombok/不喜欢它,文档也包含
@Builder