Как пометить метод обязательный? - PullRequest
8 голосов
/ 03 февраля 2012

Предположим, вы создаете имена классов Person, используя шаблон Builder, и предположим, что класс Builder содержит методы body(), head(), arms() и, конечно, build(), и вы рассматриваете методы head() и build() обязательно для пользователя этого класса.

Мы бы хотели как-то пометить эти методы как обязательные, если это возможно, используя аннотации. Если пользователь этого класса пытается создать экземпляр Person, но забыл вызвать любой из этих методов, мы хотели бы получить какое-то предупреждение - либо от компилятора java, либо, возможно, от Eclipse или Maven, которые мы используем для создания нашего проекты - любой из них будет делать.

Возможно ли это сделать? Какой способ вы бы предложили?

Ответы [ 6 ]

20 голосов
/ 03 февраля 2012

Вот пример использования различных типов, чтобы сделать некоторые части обязательными (это также делает порядок вызова методов обязательным):

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;
    }
}

<ч /> Редактировать

ОП был настолько впечатлен этим ответом, что полностью написал его в блоге . Это настолько умный подход к шаблону построения, что здесь стоит упомянуть полную обработку.

3 голосов
/ 03 февраля 2012

Я считаю, что правильное использование шаблона компоновщика решит проблему, с которой вы столкнулись.

Я бы создал класс PersonBuilder, который бы содержал методы setBody() и 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(), но я предпочитаю передавать его в конструкторе.

1 голос
/ 03 февраля 2012

Почему бы не вызвать body (), head (), arms () в build () - метод, если это действительно обязательно, и вернуть Person в методе build ()?

[править]

Краткий пример:

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 {
}
}
1 голос
/ 03 февраля 2012

Нет способа с компилятором.

Вы можете создать исключение времени выполнения из метода build(), что сборщик не инициализирован должным образом (и иметь тест, который вызывается на этапе тестирования maven)

Но вы также можете build(..) принять HeadDetails объект.Таким образом, вы не можете вызвать сборку без указания обязательных параметров.

0 голосов
/ 03 февраля 2012

невозможно вызвать эти методы в конструкторе Person?

0 голосов
/ 03 февраля 2012

Может быть, внутри build() вы можете проверить, были ли вызваны все необходимые методы.Возможно, экземпляр Person имеет некоторую внутреннюю проверку работоспособности, которая инициируется build().

Конечно, это проверяет поведение во время выполнения и не является статическим анализом, как вы его описали.

...