有效 Java 中的生成器模式

2022-08-31 08:00:33

我最近开始阅读Joshua Bloch的《Effective Java》。我发现生成器模式(书中的项目 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();
    }
}

我收到以下编译器错误:

包含有效 java 的封闭实例。BuilderPattern.NutritionalFacts.Builder is required NutritionalFacts n = new NutritionalFacts.Builder(10).carbo(23).fat(1).build();

我不明白这个信息是什么意思。请解释。上面的代码类似于布洛赫在他的书中提出的例子。


答案 1

使生成器成为类。然后它会工作。如果它是非静态的,它将需要一个其所属类的实例 - 关键是不要有它的实例,甚至禁止在没有构建器的情况下创建实例。static

public class NutritionFacts {
    public static class Builder {
    }
}

参考:嵌套类


答案 2

您应该将 Builder 类设置为静态,并且还应该使字段成为最终值,并具有获取这些值的 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();

推荐