Шаблон строителя в эффективной Ява


Я недавно начал читать эффективную Java Джошуа Блоха. Я нашел идею шаблона Builder [пункт 2 в книге] действительно интересной. Я попытался реализовать его в своем проекте, но были ошибки компиляции. Ниже в сущности то, что я пытался сделать:

класс с несколькими атрибутами и его класс строителя:

public class NutritionalFacts {
    private int sodium;
    private int fat;
    private int carbo;

    public class Builder {
        private int sodium;
        private int fat;
        private int carbo;

        public Builder(int s) {
            this.sodium = s;
        }

        public Builder fat(int f) {
            this.fat = f;
            return this;
        }

        public Builder carbo(int c) {
            this.carbo = c;
            return this;
        }

        public NutritionalFacts build() {
            return new NutritionalFacts(this);
        }
    }

    private NutritionalFacts(Builder b) {
        this.sodium = b.sodium;
        this.fat = b.fat;
        this.carbo = b.carbo;
    }
}

класс, где я пытаюсь использовать класс выше:

public class Main {
    public static void main(String args[]) {
        NutritionalFacts n = 
            new NutritionalFacts.Builder(10).carbo(23).fat(1).build();
    }
}

Я получаю следующий компилятор ошибка:

заключительный экземпляр, содержащий эффективно.BuilderPattern.Питательные вещества.Строитель требуемый NutritionalFacts п = новый Питательные вещества.Строитель(10).Карбо(23).жира(1).построить();

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

8   126   2011-02-15 20:48:24

8 ответов:

сделать сайт static класса. Тогда это сработает. Если он нестатичен, ему потребуется экземпляр его класса - владельца-и дело не в том, чтобы иметь экземпляр этого, и даже запретить создавать экземпляры без строителя.

public class NutritionFacts {
    public static class Builder {
    }
}

ссылки: вложенные классы

вы должны сделать класс Builder статическим, а также вы должны сделать поля окончательными и иметь геттеры для получения этих значений. Не предоставляйте установщики для этих значений. Таким образом, ваш класс будет совершенно неизменным.

public class NutritionalFacts {
    private final int sodium;
    private final int fat;
    private final int carbo;

    public int getSodium(){
        return sodium;
    }

    public int getFat(){
        return fat;
    }

    public int getCarbo(){
        return carbo;
    }

    public static class Builder {
        private int sodium;
        private int fat;
        private int carbo;

        public Builder sodium(int s) {
            this.sodium = s;
            return this;
        }

        public Builder fat(int f) {
            this.fat = f;
            return this;
        }

        public Builder carbo(int c) {
            this.carbo = c;
            return this;
        }

        public NutritionalFacts build() {
            return new NutritionalFacts(this);
        }
    }

    private NutritionalFacts(Builder b) {
        this.sodium = b.sodium;
        this.fat = b.fat;
        this.carbo = b.carbo;
    }
}

и теперь вы можете установить свойства следующим образом:

NutritionalFacts n = new NutritionalFacts.Builder().sodium(10).carbo(15).
fat(5).build();

чтобы создать внутренний конструктор в Intellij IDEA, проверьте этот плагин:https://github.com/analytically/innerbuilder

вы пытаетесь получить доступ к нестатическому классу статическим способом. Изменить Builder to static class Builder и это должно работать.

пример использования вы даете не потому, что нет экземпляра Builder присутствует. Статический класс для всех практических целей всегда создается. Если вы не сделаете его статичным, вам нужно будет сказать:

Widget = new Widget.Builder(10).setparm1(1).setparm2(3).build();

потому что вам нужно будет построить новый Builder каждый раз.

вам нужно объявить Builder внутренний класс, как static.

посмотреть документацию для нестатические внутренние классы и статические внутренние классы.

в основном нестатических внутренних классов экземпляры не могут существовать без экземпляра внешнего класса.

класс Builder должен быть статическим. У меня нет времени прямо сейчас, чтобы проверить код за пределами этого, но если он не работает, дайте мне знать, и я посмотрю еще раз.

это означает, что вы не можете создать тип enclose. Это означает, что сначала вам нужно создать экземпляр "родительского" класса, а затем из этого экземпляра вы можете создать вложенные экземпляры класса.

NutritionalFacts n = new NutritionalFacts()

Builder b = new n.Builder(10).carbo(23).fat(1).build();

Вложенные Классы

Я лично предпочитаю использовать другой подход, когда у вас есть 2 разных классов. Так что вам не нужен никакой статический класс. Это в основном, чтобы избежать писать Class.Builder когда вы должны создать новый экземпляр.

public class Person {
    private String attr1;
    private String attr2;
    private String attr3;

    // package access
    Person(PersonBuilder builder) {
        this.attr1 = builder.getAttr1();
        // ...
    }

    // ...
    // getters and setters 
}

public class PersonBuilder (
    private String attr1;
    private String attr2;
    private String attr3;

    // constructor with required attribute
    public PersonBuilder(String attr1) {
        this.attr1 = attr1;
    }

    public PersonBuilder setAttr2(String attr2) {
        this.attr2 = attr2;
        return this;
    }

    public PersonBuilder setAttr3(String attr3) {
        this.attr3 = attr3;
        return this;
    }

    public Person build() {
        return new Person(this);
    }
    // ....
}

Итак, вы можете использовать свой конструктор следующим образом:

Person person = new PersonBuilder("attr1")
                            .setAttr2("attr2")
                            .build();