有效Java中的构建器模式

我最近开始阅读Joshua Bloch撰写的Effective 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();
    }
}
我收到以下编译器错误:   包含的封闭实例   effectivejava.BuilderPattern.NutritionalFacts.Builder   是必须的                   NutritionalFacts n = new   NutritionalFacts.Builder(10).carbo(23).fat(1).build(); 我不明白这个消息是什么意思。请解释。上面的代码类似于Bloch在他的书中提出的例子。     
已邀请:
使建设者成为一个
static
类。然后它会工作。如果它是非静态的,那么它将需要一个拥有它的实例 - 并且要点不是拥有它的实例,甚至禁止在没有构建器的情况下创建实例。
public class NutritionFacts {
    public static class Builder {
    }
}
参考:嵌套类     
您应该将Builder类设置为静态,并且您应该将字段设为final并使getter获取这些值。不要为这些值提供setter。通过这种方式,你的课将是完全不可改变的。
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
改为
static class Builder
,它应该有效。 您提供的示例用法失败,因为没有
Builder
的实例。始终实例化用于所有实际目的的静态类。如果你不使它静止,你需要说:
Widget = new Widget.Builder(10).setparm1(1).setparm2(3).build();
因为你每次都需要建造一个新的
Builder
。     
你需要将
Builder
内部类声明为
static
。 请参阅非静态内部类和静态内部类的一些文档。 基本上,如果没有附加的外部类实例,非静态内部类实例就不可能存在。     
Builder类应该是静态的。我现在没有时间实际测试代码,但如果它不起作用,请告诉我,我会再看看。     
这意味着你不能创建封闭类型。这意味着首先必须先调用“父”类的实例,然后从此实例中创建嵌套类实例。
NutritionalFacts n = new NutritionalFacts()

Builder b = new n.Builder(10).carbo(23).fat(1).build();
嵌套类     
一旦你有了一个想法,在实践中,你可能会发现lombok的
@Builder
更方便。
@Builder
允许您使用以下代码自动生成使您的类可实例化所需的代码:
Person.builder()
  .name("Adam Savage")
  .city("San Francisco")
  .job("Mythbusters")
  .job("Unchained Reaction")
 .build(); 
官方文档:https://www.projectlombok.org/features/Builder     
当你有两个不同的类时,我个人更喜欢使用另一种方法。所以你不需要任何静态类。这基本上是为了避免在必须创建新实例时写入
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();
    

要回复问题请先登录注册