猿问

子类化Java Builder类

给这篇Dr Dobbs文章,特别是Builder Pattern,我们如何处理子类化Builder的情况?以我们想要子类化添加GMO标签的示例的简化版本为例,一个简单的实现将是:


public class NutritionFacts {                                                                                                    


    private final int calories;                                                                                                  


    public static class Builder {                                                                                                

        private int calories = 0;                                                                                                


        public Builder() {}                                                                                                      


        public Builder calories(int val) { calories = val; return this; }                                                                                                                        


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

    }                                                                                                                            


    protected NutritionFacts(Builder builder) {                                                                                  

        calories = builder.calories;                                                                                             

    }                                                                                                                            

}现在,我们可以编写如下代码:


GMOFacts.Builder b = new GMOFacts.Builder();

b.GMO(true).calories(100);

但是,如果我们得到错误的订单,那一切都会失败:


GMOFacts.Builder b = new GMOFacts.Builder();

b.calories(100).GMO(true);

问题当然是NutritionFacts.Builder返回a NutritionFacts.Builder而不是a GMOFacts.Builder,所以我们如何解决这个问题,还是有更好的模式可以使用?

白衣非少年
浏览 685回答 3
3回答

阿波罗的战车

您可以使用泛型来解决它。我认为这被称为“奇怪的反复出现的通用模式”使基类构建器方法的返回类型成为通用参数。public class NutritionFacts {&nbsp; &nbsp; private final int calories;&nbsp; &nbsp; public static class Builder<T extends Builder<T>> {&nbsp; &nbsp; &nbsp; &nbsp; private int calories = 0;&nbsp; &nbsp; &nbsp; &nbsp; public Builder() {}&nbsp; &nbsp; &nbsp; &nbsp; public T calories(int val) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; calories = val;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return (T) this;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public NutritionFacts build() { return new NutritionFacts(this); }&nbsp; &nbsp; }&nbsp; &nbsp; protected NutritionFacts(Builder<?> builder) {&nbsp; &nbsp; &nbsp; &nbsp; calories = builder.calories;&nbsp; &nbsp; }}现在使用派生类构建器作为泛型参数来实例化基础构建器。public class GMOFacts extends NutritionFacts {&nbsp; &nbsp; private final boolean hasGMO;&nbsp; &nbsp; public static class Builder extends NutritionFacts.Builder<Builder> {&nbsp; &nbsp; &nbsp; &nbsp; private boolean hasGMO = false;&nbsp; &nbsp; &nbsp; &nbsp; public Builder() {}&nbsp; &nbsp; &nbsp; &nbsp; public Builder GMO(boolean val) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; hasGMO = val;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return this;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public GMOFacts build() { return new GMOFacts(this); }&nbsp; &nbsp; }&nbsp; &nbsp; protected GMOFacts(Builder builder) {&nbsp; &nbsp; &nbsp; &nbsp; super(builder);&nbsp; &nbsp; &nbsp; &nbsp; hasGMO = builder.hasGMO;&nbsp; &nbsp; }}
随时随地看视频慕课网APP
我要回答