zoukankan      html  css  js  c++  java
  • 二、抽象层的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()返回子类
  • 相关阅读:
    “人工智能”前景:只有人工,没有智能
    google scholar vs baidu scholar-what is your problem
    springSecurity使用
    springMVC中的HttpSession与Model
    mybatis关于Criteria的一点小坑。。。
    MyBatis的Mapper接口以及Example的实例函数及详解
    被springSecurity坑哭的一天
    Mybatis-Generator
    Redis五种数据类型应用场景
    springboot_自动配置原理
  • 原文地址:https://www.cnblogs.com/tabCtrlShift/p/9417157.html
Copyright © 2011-2022 走看看