我一直想知道是否可以更优雅地使用可选参数来做生成器:
我有什么:带有姓名,ID,年龄的对象。
我有复杂的年龄条件,我想在该条件成功后将其发送给构建者,但我希望它优雅地带有一个参数。
到目前为止,我拥有的:
Builder.name("name").id("id").age(age, complexCondition).build();
或
Builder builder = Builder.name("name").id("id");
if(complexCondition){
builder.age(age);
}
有没有更好的选择?我想解决我拥有的条件,而无需过度设计构建器,并且没有为每个复杂的条件检查进行过度编码。
upd:我正在寻找的解决方案没有:
a( 将 complexCheck 或布尔值传递给构建者 - 而不是他的工作,通过定义进行检查
b( 每个条件不添加 3 行,检查调用生成器的内部方法
我的回答是保持简单。构建器的职责是构建一个对象。不提供复杂的 DSL 来评估条件。所以你的第二个片段非常好。
为了避免许多if
检查与对构建器的调用交错,您所需要的只是将这些检查的代码提取到方法中。所以你可以从
Builder builder = Builder.name("name").id("id");
if (complexCondition) {
builder.age(age);
}
自
Integer age = null; // or whatever other default value you want
if (complexCondition) {
age = somethingElse;
}
Builder builder = Builder.name("name").id("id").age(age);
最后,bu 将 4 首行提取到方法计算并返回年龄,
Builder builder = Builder.name("name").id("id").age(computeAge());
我个人更喜欢它以以下方式缩进,IMO 使其更具可读性且更易于调试:
Builder builder = Builder.name("name")
.id("id")
.age(computeAge());
我倾向于使用三元运算符来延续链。
因此,假设我在上面有您的情况:
Builder builder = Builder
.name("name")
.id("id");
builder = (complexCondition ? builder.age(age) : builder)
.occupation("brick-layer")
.disposition("angry");
这样,您可以在链中插入可选项目,而不会完全中断其流程。如果它很长,显然在多行上格式化它。
您可以做的另一件事是在年龄方法中处理 null,如下所示:
Builder builder = Builder
.name("name")
.id("id")
.age(complexCondition ? age : null);
当然,在内部,您的年龄方法如下所示:
public Builder age(Integer age) {
if (age != null) {
this.age = age;
}
return this;
}
好吧,如果你想要每个方法调用一个参数,你可以拆分
Builder.name("name").id("id").age(age, complexCondition).build();
到
Builder.name("name").id("id").age(age).ageCondition(complexCondition).build();
您可能需要考虑将complexCondition
设为Predicate<Something>
(其中Something
是用于评估条件的某种类型的实例(。这样,当你调用Builder
的build()
时,你只在提供了年龄参数的情况下计算复杂条件。
build
方法可能如下所示:
public SomeClass build() {
SomeClass obj = new SomeClass();
obj.setName(name);
if (age != null && someCondition != null && someCondition.test(something)) {
obj.setAge(age);
}
return obj;
}
我不确定something
会是什么。这取决于您复杂状况的性质。
或者,如果您希望条件是可选的:
public SomeClass build() {
SomeClass obj = new SomeClass();
obj.setName(name);
if (age != null) {
if (someCondition != null)) {
if (someCondition.test(something)) {
obj.setAge(age);
}
} else {
obj.setAge(age);
}
}
return obj;
}
警告!大多数构建器要求您重新分配构建器变量。你下面的例子会给你带来麻烦。
Builder builder = Builder.name("name").id("id");
if(complexCondition){
builder.age(age);
}
您应该习惯这种格式。
Builder builder = Builder.name("name").id("id");
if(complexCondition){
builder = builder.age(age);
}