如何标记方法必须?

时间:2012-02-03 09:20:12

标签: java design-patterns annotations builder

假设您使用构建器模式创建类名Person,并假设Builder类包含方法body()head()arms(),当然还包含build()并且您考虑方法head()build()对此类用户来说是强制性的。

我们希望以某种方式标记这些方法是强制性的,如果可能的话使用注释。如果这个类的用户试图构建一个Person实例但是忘了调用这些方法中的任何一个,我们希望得到某种警告 - 无论是来自java编译器,还是来自Eclipse或Maven,我们用它来构建我们的项目 - 其中任何一项都可以。

有可能吗?你会建议哪种方式?

6 个答案:

答案 0 :(得分:19)

以下是使用不同类型强制某些部分的示例(它还使您调用方法的顺序成为强制性):

package test;

import test.StepOne.StepThree;
import test.StepOne.StepTwo;
import test.StepOne.LastStep;

public class TestBuilder {

    public static void main(String[] args) {

        String person1 = PersonBuilder.newInstance().head("head").body("body").arm("arm").leg("leg").build();

        String person2 = PersonBuilder.newInstance().head("head").body("body").arm("arm").build();

    }

}

interface StepOne {

    // mandatory
    StepTwo head(String head);

    interface StepTwo {
        // mandatory
        StepThree body(String body);
    }

    interface StepThree {
        // mandatory
        LastStep arm(String arm);
    }

    // all methods in this interface are not mandatory
    interface LastStep {
        LastStep leg(String leg);
        String build();
    }

}

class PersonBuilder implements StepOne, StepTwo, StepThree, LastStep {

    String head;
    String body;
    String arm;
    String leg;

    static StepOne newInstance() {
        return new PersonBuilder();
    }

    private PersonBuilder() {
    }



    public StepTwo head(String head) {
        this.head = head;
        return this;
    }

    public LastStep arm(String arm) {
        this.arm = arm;
        return this;
    }

    public StepThree body(String body) {
        this.body = body;
        return this;
    }

    public LastStep leg(String leg) {
        this.leg = leg;
        return this;
    }

    public String build() {
        return head + body + arm + leg;
    }
}

<小时/> 的修改

OP对这个答案印象深刻,他在 blog完全写下了这个答案。对于建造者模式这是一个聪明的看法,这里应该引用一个完整的处理方法。

答案 1 :(得分:3)

我相信正确使用构建器模式可以解决您遇到的问题。

我会创建包含方法PersonBuildersetBody()以及其他所有可选参数setter方法的类setArms()。构建器的构造函数将采用所需的参数。然后方法build()将返回Person的新实例。

public class PersonBuilder
{
    private final Head head;
    private Body body;
    private Arms arms;

    public PersonBuilder(Head head)
    {
        this.head = head;
    }

    public void setBody(Body body)
    {
        this.body = body;
    }

    public void setArms(Arms arms)
    {
        this.arms = arms;
    }

    public Person build()
    {
        return new Person(head, body, arms);
    }
}

或者,您可以将Head参数传递给方法build(),但我更喜欢在构造函数中传递它。

答案 2 :(得分:1)

无法使用编译器。

你可以做的是从build()方法抛出一个运行时异常,它没有正确初始化构建器(并且在maven测试阶段有一个测试)

但您也可以build(..)接受HeadDetails个对象。这样,tou就可以在不指定强制性参数的情况下调用构建。

答案 3 :(得分:1)

为什么不在build()中调用body(),head(),arms() - 如果它确实是强制的并且在build()方法中返回Person,那么该方法是什么?

[编辑]

简短的例子:

public class Builder {

private final String bodyProp;

private final String headProp;

private final String armsProp;

private String hearProps;

public Builder(String bodyProp, String headProp, String armsProp) {
    super();
    this.bodyProp = bodyProp; // check preconditions here (eg not null)
    this.headProp = headProp;
    this.armsProp = armsProp;
}

public void addOptionalHair(String hearProps) {
    this.hearProps = hearProps;
}

public Person build() {
    Person person = new Person();

    person.setBody(buildBody());
    // ...

    return person;
}



private Body buildBody() {
    // do something with bodyProp
    return new Body();
}


public static class Person {

    public void setBody(Body buildBody) {
        // ...
    }
}

public static class Body {
}
}

答案 4 :(得分:0)

也许在build()内,您可以检查是否已调用所有必需的方法。因为Person实例有一些由build()触发的内部健全性检查。

当然,这会检查运行时行为,并且不会像您描述的那样进行静态分析。

答案 5 :(得分:0)

是不可能在Person的构造函数中调用这些方法的?