【发布时间】:2019-11-15 19:34:05
【问题描述】:
我有这个类结构:
Stuff
/ \
Food
|
FastFood Drink
| |
Pizza Juice
/ \ / \
| SicilianPizza | OrangeJuice
| AppleJuice
CaliforniaPizza
我可以使用这样的构建器创建披萨和果汁对象:
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();
builder 的每个 setter 方法都返回正确的对象:
我想创建一个可以接受FastFood.Builder 对象的方法,并使用它来创建一个FastFood 对象,然后将其传递给另一个方法:
public void makeFat(FastFood fastFood) {...}
但我不能:setter 方法不返回 FastFood,而是返回其父项:
我的泛型有问题吗?怎么可能实现?
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();
}
public FastFood testFood(FastFood.Builder fastFoodBuilder) {
//return fastFoodBuilder.setMealType("fd").addOlives(true).setPrice(20).build();
}
public void makeFat(FastFood fastFood) {}
}
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 FastFood extends Food {
protected int harm;
protected FastFood() {}
public abstract class Builder<T extends Builder<T>> extends Food.Builder<T> {
protected abstract FastFood build();
protected abstract T self();
public T setHarm(int harm) {
FastFood.this.harm = harm;
return self();
}
}
}
abstract class Pizza extends FastFood {
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 FastFood.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 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;
}
}
}
【问题讨论】:
-
从表中检索到的前 10 个条目对于“amenities”具有 NULL 或空字符串并不表示错误。您不能在消火栓处点三明治,这不是错误。试试
SELECT amenity FROM planet_osm_point where amenity is not null and amenity <> ''LIMIT 10 -
这似乎是你的IDE的问题。 Eclipse 将
FastFood2推断为build()。然而,如果您将方法签名转换为FastFood testBuilder(FastFood2.Builder<? extends FastFood2.Builder<?>> builder),您的 IDE 可能会恢复。 -
@CoronA 抱歉,我意识到我的最后一个代码更难使用并对其进行了编辑。现在可以一次全部复制粘贴。我现在就试试你的建议!
标签: java generics design-patterns