• 二、抽象层的Builder模式


    Builder模式非常适合类层次结构。 使用平行层次的builder,每个嵌套在相应的类中。 抽象类有抽象的builder; 具体的类有具体的builder。 例如,考虑代表各种比萨饼的根层次结构的抽象类:

    // Builder pattern for class hierarchies
    
    import java.util.EnumSet;
    import java.util.Objects;
    import java.util.Set;
    
    public abstract class Pizza {
        public enum Topping {HAM, MUSHROOM, ONION, PEPPER, SAUSAGE}
        final Set<Topping> toppings;
        
        abstract static class Builder<T extends Builder<T>> {
            EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class);
    
            public T addTopping(Topping topping) {
                toppings.add(Objects.requireNonNull(topping));
                return self();
            }
            
            abstract Pizza build();
            
            // Subclasses must override this method to return "this"
            protected abstract T self();
        }
    
        Pizza(Builder<?> builder) {
            toppings = builder.toppings.clone(); // See Item 50
        }
    }

    请注意,Pizza.Builder是一个带有递归类型参数( recursive type parameter)(条目 30)的泛型类型。 这与抽象的self方法一起,允许方法链在子类中正常工作,而不需要强制转换。

    请注意,Pizza.Builder是一个带有递归类型参数( recursive type parameter)(条目 30)的泛型类型。 这与抽象的self方法一起,允许方法链在子类中正常工作,而不需要强制转换。 Java缺乏自我类型的这种变通解决方法被称为模拟自我类型(simulated self-type)的习惯用法。

    这里有两个具体的Pizza的子类,其中一个代表标准的纽约风格的披萨,另一个是半圆形烤乳酪馅饼。前者有一个所需的尺寸参数,而后者则允许指定酱汁是否应该在里面或在外面:

    import java.util.Objects;
    
    public class NyPizza extends Pizza {
        public enum Size { SMALL, MEDIUM, LARGE }
        private final Size size;
    
        public static class Builder extends Pizza.Builder<Builder> {
            private final Size size;
    
            public Builder(Size size) {
                this.size = Objects.requireNonNull(size);
            }
    
            @Override public NyPizza build() {
                return new NyPizza(this);
            }
    
            @Override protected Builder self() {
                return this;
            }
        }
    
        private NyPizza(Builder builder) {
            super(builder);
            size = builder.size;
        }
    }
    
    public class Calzone extends Pizza {
        private final boolean sauceInside;
        
        public static class Builder extends Pizza.Builder<Builder> {
            private boolean sauceInside = false; // Default
    
            public Builder sauceInside() {
                sauceInside = true;
                return this;
            }
            
            @Override public Calzone build() {
                return new Calzone(this);
            }
            
            @Override protected Builder self() {
                return this; 
            }
        }
        
        private Calzone(Builder builder) {
            super(builder);
            sauceInside = builder.sauceInside;
        }
    }

    请注意,每个子类builder中的build方法被声明为返回正确的子类:NyPizza.Builderbuild方法返回NyPizza,而Calzone.Builder中的build方法返回Calzone。 这种技术,其一个子类的方法被声明为返回在超类中声明的返回类型的子类型,称为协变返回类型( covariant return typing)。 它允许客户端使用这些builder,而不需要强制转换。

    这些“分层builder”的客户端代码基本上与简单的NutritionFacts builder的代码相同。为了简洁起见,下面显示的示例客户端代码假设枚举常量的静态导入:

    NyPizza pizza = new NyPizza.Builder(SMALL)
            .addTopping(SAUSAGE).addTopping(ONION).build();
    Calzone calzone = new Calzone.Builder()
            .addTopping(HAM).sauceInside().build();
    .build()返回子类
  • 相关阅读:
    react className 有多个值时的处理 / react 样式使用 百分比(%) 报错
    更改 vux Tabbar TabbarItem标题下方的文字激活时的颜色
    angular 图片加载失败 情况处理? 如何在ionic中加载本地图片 ?
    angular 资源路径问题
    webpack 项目实战
    百度地图 创建 自定义控件(vue)
    function 之 arguments 、call 、apply
    手写 redux 和 react-redux
    ARC以及MRC中setter方法的差异
    运行时中给一个对象绑定另外一个对象
  • 原文地址:https://www.cnblogs.com/tabCtrlShift/p/9417157.html
Copyright © 2020-2023  润新知