Шаблон Builder в эффективной Java
недавно я начал читать эффективную Java Джошуа Блоха. Я нашел идею шаблона Builder [пункт 2 в книге] действительно интересной. Я попытался реализовать его в своем проекте, но были ошибки компиляции. В сущности, я пытался сделать следующее:--3-->
класс с несколькими атрибутами и его класс builder:
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();
}
}
Я получаю следующий компилятор ошибка:
заключительный экземпляр, содержащий effectivejava.BuilderPattern.NutritionalFacts.Строитель требуемый NutritionalFacts N = новый NutritionalFacts.Строитель(10).Карбо(23).жира(1).build();
Я не понимаю, что значит это сообщение. Пожалуйста объяснить. Приведенный выше код аналогичен примеру, предложенному Блохом в его книге.
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
внутренний класс as 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();