生成器与条件包含元素

时间:2018-01-21 15:38:37

标签: java design-patterns builder

我一直想知道可以更优雅地使用可选参数做Builder:

我拥有的:具有姓名,身份,年龄的对象。

我有包含年龄的复杂条件,我想在成功的条件下将它发送给建造者,但我希望它有一个带有一个参数的优雅的衬垫。

到目前为止:

 Builder.name("name").id("id").age(age, complexCondition).build();

 Builder builder = Builder.name("name").id("id");
 if(complexCondition){
     builder.age(age);
 }

还有更好的选择吗?我想解决我拥有它的条件,而不需要过度设计构建器,也不需要对每个复杂的条件检查进行过度编码。

upd:我正在寻找的是没有的解决方案:

a)将complexChecks或booleans传递给构建者 - 而不是按照定义检查他的工作

b)每个条件不添加3行检查调用构建器

的方法内部

4 个答案:

答案 0 :(得分: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);

最后,将4个第一行提取到计算并返回年龄的方法

Builder builder = Builder.name("name").id("id").age(computeAge());

我个人更喜欢用以下方式缩进,IMO让它更易读,更容易调试:

Builder builder = Builder.name("name")
                         .id("id")
                         .age(computeAge());

答案 1 :(得分:1)

好吧,如果你想为每个方法调用一个参数,你可以拆分

Builder.name("name").id("id").age(age, complexCondition).build();

Builder.name("name").id("id").age(age).ageCondition(complexCondition).build();

您可能需要考虑将complexCondition设为Predicate<Something>(其中Something是某种类型的实例,用于评估条件)。这样,当您调用Builder&#39; 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;
}

答案 2 :(得分:0)

我倾向于使用三元运算符来延续链条。

所以假设我有你的情况:

Builder builder = Builder
    .name("name")
    .id("id");
builder = (complexCondition ? builder.age(age) : builder)
    .occupation("brick-layer")
    .disposition("angry");

这样,您就可以在链中插入可选项目而不会完全中断它的流程。如果它很长,显然可以将其格式化为多行。

你可以做的另一件事是在你的 age 方法中处理 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;
}

答案 3 :(得分:-1)

警告!大多数构建器要求您重新分配构建器变量。下面的示例将给您带来麻烦。

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);
 }
相关问题