我基于此answer实现了模式
我有以下抽象配置:
public abstract class AbstractConfig {
public static abstract class Builder<B extends Builder<B>> {
private int calories = 0;
public Builder() {
}
public B setCalories(int calories) {
this.calories = calories;
return (B) this;
}
public abstract AbstractConfig build();
}
private int calories = 0;
protected AbstractConfig(final Builder builder) {
calories = builder.calories;
}
}
我有以下具体配置:
public class DialogConfig extends AbstractConfig {
public static class DialogConfigBuilder<B extends DialogConfigBuilder<B>> extends Builder<B> {
private double width;
private double height;
public DialogConfigBuilder() {
//does nothing.
}
public B setWidth(final double value) {
width = value;
return (B) this;
}
public B setHeight(final double value) {
height = value;
return (B) this;
}
public DialogConfig build() {
return new DialogConfig(this);
}
}
private final double width;
private final double height;
protected DialogConfig(final DialogConfigBuilder builder) {
super(builder);
width = builder.width;
height = builder.height;
}
public double getWidth() {
return width;
}
public double getHeight() {
return height;
}
}
这就是我的使用方式
DialogConfig config = new DialogConfig.DialogConfigBuilder()
.setWidth(0)
.setCalories(0)
.setHeight(0) //X LINE
.build();
在X行,我得到-找不到符号方法setHeight。我怎么了
编辑-我将有一个ExtendedDialogConfig和一个必须扩展DialogConfig等的类。我的意思是,将会有其他子类。
最佳答案
您首先要将setCalories()
更改为:
public Builder<B> setCalories(int calories) {
this.calories = calories;
return this;
}
摆脱那种偏见和警告。现在仔细看看。您返回一个生成器。这段代码不知道将来的子类。它仅返回该基本构建器的实例。
因此,当您进行链接呼叫时:
.setHeight(0) .build();
那将返回那个基础建造者。然后调用
build()
-这将建立一个抽象配置。但是您想将其分配给更特定的DialogConfig。因此错误。一个(丑陋的)解决方法:
DialogConfig.DialogConfigBuilder<?> builder = new DialogConfig.DialogConfigBuilder<>().setHeight(0);
builder.setCalories(0);
...config = builder.build();
还有一个解决方案-再次修改
setCalories()
:@SuppressWarnings("unchecked")
public <T extends B> T setCalories(int calories) {
this.calories = calories;
return (T) this;
}
修复编译错误;并允许链接
setCalories()
调用。剩下的摆脱演员/抑制的练习留给读者练习。记录在案的“完整”解决方案,包括摆脱原始类型和其他警告的所有调整:
abstract class AbstractConfig {
public static abstract class Builder<B extends Builder<B>> {
private int calories = 0;
@SuppressWarnings("unchecked")
public <T extends B> T setCalories(int calories) {
this.calories = calories;
return (T) this;
}
public abstract AbstractConfig build();
}
private int calories = 0;
public int getCalories() { return calories; }
protected <B extends Builder<B>> AbstractConfig(final Builder<B> builder) {
calories = builder.calories;
}
}
final class DialogConfig extends AbstractConfig {
public static class DialogConfigBuilder<B extends DialogConfigBuilder<B>> extends Builder<B> {
private double width;
private double height;
public DialogConfigBuilder<B> setWidth(final double value) {
width = value;
return this;
}
public DialogConfigBuilder<B> setHeight(final double value) {
height = value;
return this;
}
public DialogConfig build() {
return new DialogConfig(this);
}
}
private final double width;
private final double height;
protected <B extends DialogConfigBuilder<B>> DialogConfig(final DialogConfigBuilder<B> builder) {
super(builder);
width = builder.width;
height = builder.height;
}
public double getWidth() { return width; }
public double getHeight() { return height; }
}
public class Builders {
public static void main(String[] args) {
DialogConfig config = new DialogConfig.DialogConfigBuilder<>().setHeight(0).setCalories(0).build();
System.out.println(config);
}
}