Builder模式中的嵌套泛型:如何实现和避免类型擦除(ascii树,图片)

解析器

我一直在寻找实现具有许多子类的 Builder 模式,并通过@Josemy找到了这个答案但是,它只有 1 个级别的子类:. 我试图将构建器模式用于更复杂的层次结构,但失败了。Pizza -> SomePizza

我有以下类层次结构:

                Stuff
              /       \
   Food                     Drink
     |                        |
   Pizza                    Juice
  /     \                   /    \
 |     SicilianPizza       |    OrangeJuice
 |                      AppleJuice
CaliforniaPizza

每个类都有一个应该设置的字段,其中一些字段是强制性的 (ob) 并且必须传递,有些是可选的 (op) 并且可以通过构建器设置:

Stuff -> double price (op)
  Food -> String mealType (op)
    Pizza -> List<String> toppings (op), int size (ob)
      CaliforniaPizza -> boolean addOlives (op)
      SicilianPizza -> boolean addCheese (op)
  Drink -> double density (ob), double alcoholVolume (op)
    Juice -> String color (op)
      AppleJuice -> String appleColor (op)
      OrangeJuice -> int orangeSize (op)

我使用建造者来建造比萨饼和饮料:

TestStuff.java

public class TestStuff {
    public static void main(String[] args) {
        CaliforniaPizza californiaPizze = CaliforniaPizza.builder(2)
                                    .addTopping("Tomatoes").addOlives(true).build();
        SicilianPizza sicilianPizza = SicilianPizza.builder(1)
                                    .addTopping("Bacon").addCheese(false).build();

        AppleJuice appleJuice = AppleJuice.builder(40)
                                    .setPrice(120).setAlcoholVolume(0).setAppleColor("yellow").build();
        OrangeJuice orangeJuice = OrangeJuice.builder(35).setOrangeSize(8).build();
    }
}

这些是我的课程:

东西.java

public abstract class Stuff {
    protected double price;

    protected Stuff()  {}

    protected abstract class Builder<T extends Builder>  {
        protected abstract Stuff build();
        protected abstract T self();

        public T setPrice(double price)  {
            Stuff.this.price = price;
            return (T) self();
        }
    }
}

食物.java :

public abstract class Food extends Stuff {
    protected String mealType; //breakfast/dinner/etc

    protected Food()  {}

    public abstract class Builder<T extends Builder> extends Stuff.Builder<Builder> {
        protected abstract Food build();
        protected abstract T self();

        public T setMealType(String mealType)  {
            Food.this.mealType = mealType;
            return (T) self();
        }
    }
}

比萨.java :

public abstract class Pizza extends Food {
    protected List<String> toppings = new ArrayList<>();  //optional
    protected int size;  //obligatory

    protected Pizza(int size)  {this.size = size;}

    public abstract class Builder<T extends Builder> extends Food.Builder<Builder>  {
        public T addTopping(String topping)  {
            toppings.add(topping);
            return (T) self();
        }
    }
}

CaliforniaPizza.java :

public class CaliforniaPizza extends Pizza {
    private boolean addOlives;

    private CaliforniaPizza(int size) {super(size);}

    public static Builder builder(int size)  {return new CaliforniaPizza(size).new Builder();}

    public class Builder extends Pizza.Builder<Builder>  {
        @Override
        public CaliforniaPizza build()  {
            return CaliforniaPizza.this;
        }

        @Override
        public Builder self()  {return this;}

        public Builder addOlives(boolean addOlives)  {
            CaliforniaPizza.this.addOlives = addOlives;
            return this;
        }
    }
}

西西里披萨.java :

public class SicilianPizza extends Pizza {
    private boolean addCheese;

    private SicilianPizza(int size)  {super(size);}

    public static Builder builder(int size)  {
        return new SicilianPizza(size).new Builder();
    }

    public class Builder extends Pizza.Builder<Builder>  {
        @Override
        public SicilianPizza build()  {return SicilianPizza.this;}

        @Override
        public Builder self()  {return this;}

        public Builder addCheese(boolean addCheese)  {
            SicilianPizza.this.addCheese = addCheese;
            return this;
        }
    }
}

饮料.java :

public abstract class Drink extends Stuff {
    protected double density;
    protected double alcoholVolume;

    protected Drink(double density)  {this.density = density;}

    public abstract class Builder<T extends Builder> extends Stuff.Builder<Builder>  {
        protected abstract Drink build();
        protected abstract T self();

        public T setAlcoholVolume(double alcoholVolume)  {
            Drink.this.alcoholVolume = alcoholVolume;
            return (T) self();
        }
    }
}

果汁.java :

public abstract class Juice extends Drink {
    private String color;

    protected Juice(double density)  {super(density);}

    public abstract class Builder<T extends Builder> extends Drink.Builder<Builder>  {
        public Builder setColor(String color)  {
            Juice.this.color = color;
            return (T) self();
        }
    }
}

苹果汁.java :

public class AppleJuice extends Juice {
    private String appleColor;

    private AppleJuice(double density)  {super(density);}

    public static Builder builder(double density)  {return new AppleJuice(density).new Builder();}

    public class Builder extends Juice.Builder<Builder>  {
        @Override
        public AppleJuice build()  {
            return AppleJuice.this;
        }

        @Override
        public Builder self()  {
            return this;
        }

        public Builder setAppleColor(String appleColor)  {
            AppleJuice.this.appleColor = appleColor;
            return this;
        }
    }
}

橙汁.java :

public class OrangeJuice extends Juice{
    private int orangeSize;

    private OrangeJuice(double density)  {super(density);}

    public static Builder builder(double density)  {return new OrangeJuice(density).new Builder();}

    public class Builder extends Juice.Builder<Builder>  {
        @Override
        public OrangeJuice build()  {return OrangeJuice.this;}

        @Override
        public Builder self()  {return this;}

        public Builder setOrangeSize(int orangeSize)  {
            OrangeJuice.this.orangeSize = orangeSize;
            return this;
        }
    }
}

这段代码有几个问题:

  1. @Override注解上面build()self内部CaliforniaPizza,并SicilianPizza在观的Intellij和错误信息被高亮显示表示,方法不从其超类重写方法。虽然Juice子类中没有这样的错误
  2. 里面的这一行TestStuff
 AppleJuice appleJuice = AppleJuice.builder(40)                    
      .setPrice(120).setAlcoholVolume(0)
      .setAppleColor("yellow").build();

给出错误:setAppleColor用红色突出显示,无法解决。原因是setAlcoholVolume返回 aDrink.Builder而不是AppleJuice.Builder同时,如果我setAlcoholVolumebuilder()方法之后立即调用它会返回Juice.Builder

在此处输入图片说明

  1. 尽管果汁制造商存在问题,但至少我可以在某种程度上访问所有方法(至少如果我在 之后立即调用它们builder()。但是对于食物,我的选择是有限的:

在此处输入图片说明

那里没有食物setMealType

  1. return (T) self()Juiceand 中的setter 中一行Pizza但是,只有在内部Juice,我才会收到有关未经检查的演员的警告:

在此处输入图片说明

而在Pizza我根本没有收到任何警告。

I have suspicions that at least problems 2 and 3 have to do with type erasure. An AppleJuice.Builder gets passed to Juice.Builder as T, but then the Juice.Builder<AppleJuice.Builder> gets passed to Drink.Builder<Juice.Builder> and the information about AppleJuice gets lost. Then Drink.Builder<Juice.Builder> gets passed to Stuff.Builder<Drink.Builder> and only information about Drink.Builder is retained. Thus when I call setPrice(120) right away, it returns Drink.Builder instead of Juice.Builder. If I'm correct, what is the way to fix it? And what are the reasons behind another issues I've encountered?

Tom Hawtin - tackline

The cast

    protected abstract T self();

    public T setPrice(double price)  {
        Stuff.this.price = price;
        return (T) self();
    }

self() already returns T. The cast is unnecessary.

Unresolved methods

public abstract class Stuff {
   // ...
    protected abstract class Builder<T extends Builder>  {

Builder is a generic type, but it's used a raw type here. It needs the type parameter, like java.lang.Enum.

    protected abstract class Builder<T extends Builder<T>>  {

Again in subtypes.

public abstract class Food extends Stuff {
    // ...

    public abstract class Builder<T extends Builder> extends Stuff.Builder<Builder> 

同样在这里我们想StuffBuilderT.

    public abstract class Builder<T extends Builder> extends Stuff.Builder<T> 

@Override小号

对类型进行排序后,覆盖问题应该会消失。

编辑:

所以我已经完成并更改了代码。(添加packageimport并删除publicclassES进行编译的一个斑点。)Eclipse是满意的,除了未使用的变量。

package pizza;

import java.util.*;

class TestStuff {
    public static void main(String[] args) {
        CaliforniaPizza californiaPizze = CaliforniaPizza.builder(2)
                                    .addTopping("Tomatoes").addOlives(true).build();
        SicilianPizza sicilianPizza = SicilianPizza.builder(1)
                                    .addTopping("Bacon").addCheese(false).build();

        AppleJuice appleJuice = AppleJuice.builder(40)
                                    .setPrice(120).setAlcoholVolume(0).setAppleColor("yellow").build();
        OrangeJuice orangeJuice = OrangeJuice.builder(35).setOrangeSize(8).build();
    }
}

abstract class Stuff {
    protected double price;

    protected Stuff()  {}

    protected abstract class Builder<T extends Builder<T>>  {
        protected abstract Stuff build();
        protected abstract T self();

        public T setPrice(double price)  {
            Stuff.this.price = price;
            return self();
        }
    }
}

abstract class Food extends Stuff {
    protected String mealType; //breakfast/dinner/etc

    protected Food()  {}

    public abstract class Builder<T extends Builder<T>> extends Stuff.Builder<T> {
        protected abstract Food build();
        protected abstract T self();

        public T setMealType(String mealType)  {
            Food.this.mealType = mealType;
            return self();
        }
    }
}

abstract class Pizza extends Food {
    protected List<String> toppings = new ArrayList<>();  //optional
    protected int size;  //obligatory

    protected Pizza(int size)  {this.size = size;}

    public abstract class Builder<T extends Builder<T>> extends Food.Builder<T>  {
        public T addTopping(String topping)  {
            toppings.add(topping);
            return self();
        }
    }
}

class CaliforniaPizza extends Pizza {
    private boolean addOlives;

    private CaliforniaPizza(int size) {super(size);}

    public static Builder builder(int size)  {return new CaliforniaPizza(size).new Builder();}

    public class Builder extends Pizza.Builder<Builder>  {
        @Override
        public CaliforniaPizza build()  {
            return CaliforniaPizza.this;
        }

        @Override
        public Builder self()  {return this;}

        public Builder addOlives(boolean addOlives)  {
            CaliforniaPizza.this.addOlives = addOlives;
            return this;
        }
    }
}

class SicilianPizza extends Pizza {
    private boolean addCheese;

    private SicilianPizza(int size)  {super(size);}

    public static Builder builder(int size)  {
        return new SicilianPizza(size).new Builder();
    }

    public class Builder extends Pizza.Builder<Builder>  {
        @Override
        public SicilianPizza build()  {return SicilianPizza.this;}

        @Override
        public Builder self()  {return this;}

        public Builder addCheese(boolean addCheese)  {
            SicilianPizza.this.addCheese = addCheese;
            return this;
        }
    }
}

abstract class Drink extends Stuff {
    protected double density;
    protected double alcoholVolume;

    protected Drink(double density)  {this.density = density;}

    public abstract class Builder<T extends Builder<T>> extends Stuff.Builder<T>  {
        protected abstract Drink build();
        protected abstract T self();

        public T setAlcoholVolume(double alcoholVolume)  {
            Drink.this.alcoholVolume = alcoholVolume;
            return (T) self();
        }
    }
}

abstract class Juice extends Drink {
    private String color;

    protected Juice(double density)  {super(density);}

    public abstract class Builder<T extends Builder<T>> extends Drink.Builder<T>  {
        public Builder<T> setColor(String color)  {
            Juice.this.color = color;
            return self();
        }
    }
}
class AppleJuice extends Juice {
    private String appleColor;

    private AppleJuice(double density)  {super(density);}

    public static Builder builder(double density)  {return new AppleJuice(density).new Builder();}

    public class Builder extends Juice.Builder<Builder>  {
        @Override
        public AppleJuice build()  {
            return AppleJuice.this;
        }

        @Override
        public Builder self()  {
            return this;
        }

        public Builder setAppleColor(String appleColor)  {
            AppleJuice.this.appleColor = appleColor;
            return this;
        }
    }
}

class OrangeJuice extends Juice{
    private int orangeSize;

    private OrangeJuice(double density)  {super(density);}

    public static Builder builder(double density)  {return new OrangeJuice(density).new Builder();}

    public class Builder extends Juice.Builder<Builder>  {
        @Override
        public OrangeJuice build()  {return OrangeJuice.this;}

        @Override
        public Builder self()  {return this;}

        public Builder setOrangeSize(int orangeSize)  {
            OrangeJuice.this.orangeSize = orangeSize;
            return this;
        }
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章