有效Java中的生成器模式

Swa*_*rma 136 java design-patterns builder-pattern

我最近开始阅读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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我尝试使用上述类的类:

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

我收到以下编译器错误:

包含effectivejava.BuilderPattern.NutritionalFacts.Builder的封闭实例是必需的NutritionalFacts n = new NutritionalFacts.Builder(10).carbo(23).fat(1).build();

我不明白这个消息是什么意思.请解释.上面的代码类似于Bloch在他的书中提出的例子.

Boz*_*zho 168

使构建器成为一个static类.然后它会工作.如果它是非静态的,那么它将需要一个拥有它的实例 - 并且要点不是拥有它的实例,甚至禁止在没有构建器的情况下创建实例.

public class NutritionFacts {
    public static class Builder {
    }
}
Run Code Online (Sandbox Code Playgroud)

参考:嵌套类

  • 事实上,在本书的例子中,"Builder"是"静态的"(第2版第14页第10行). (34认同)

Raj*_*ani 27

您应该将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;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您可以按如下方式设置属性:

NutritionalFacts n = new NutritionalFacts.Builder().sodium(10).carbo(15).
fat(5).build();
Run Code Online (Sandbox Code Playgroud)


小智 13

要在Intellij IDEA中生成内部构建器,请查看此插件:https://github.com/analytically/innerbuilder

  • 这与提出的问题无关,但非常有帮助!很好找! (2认同)

Mic*_*l K 11

您正在尝试以静态方式访问非静态类.更改Builderstatic class Builder它应该工作.

您提供的示例用法失败,因为没有存在的实例Builder.始终实例化用于所有实际目的的静态类.如果你不使它静止,你需要说:

Widget = new Widget.Builder(10).setparm1(1).setparm2(3).build();
Run Code Online (Sandbox Code Playgroud)

因为你Builder每次都需要构建一个新的.


Grz*_*zki 7

您需要将Builder内部类声明为static.

请参阅非静态内部类静态内部类的一些文档.

基本上,如果没有附加的外部类实例,非静态内部类实例就不可能存在.


tor*_*ina 5

一旦有了想法,在实践中,您可能会发现lombok @Builder更加方便。

@Builder 使您可以自动生成使您的类可实例化的代码,例如:

Person.builder()
  .name("Adam Savage")
  .city("San Francisco")
  .job("Mythbusters")
  .job("Unchained Reaction")
 .build(); 
Run Code Online (Sandbox Code Playgroud)

官方文档:https : //www.projectlombok.org/features/Builder