考虑带有抽象生成器的抽象数据类:
abstract class Data {
abstract static class Builder<T extends Data> {
private String one;
protected Builder() {
this.one = null;
}
public final Builder<T> withOne(final String value) {
this.one = value;
return this;
}
protected abstract T build();
}
private final String one;
protected Data(final Builder<? extends Data> builder) {
this.one = builder.one;
}
public final String getOne() {
return this.one;
}
}
该类被扩展,其中还包括自己的扩展Builder:
public final class Extension extends Data {
public static final class ExtensionBuilder extends Data.Builder<Extension> {
private String two;
private ExtensionBuilder() {
super();
this.two = null;
}
public static final ExtensionBuilder newInstance() {
return new ExtensionBuilder();
}
public final ExtensionBuilder withTwo(final String value) {
this.two = value;
return this;
}
public final Extension build() {
return new Extension(this);
}
}
private final String two;
private Extension(final ExtensionBuilder builder) {
super(builder);
this.two = builder.two;
}
public final String getTwo() {
return this.two;
}
}
Extension 对象从两个类中获取所有方法。但是调用 setter 方法的顺序很重要。这没关系:
Extension one = Extension.ExtensionBuilder
.newInstance()
.withTwo("two")
.withOne("one")
.build();
而这会产生编译错误:
Extension two = Extension.ExtensionBuilder
.newInstance()
.withOne("one")
.withTwo("two")
.build();
我知道为什么,withOne() setter 将 Builder 对象的类型从具体类向下转换为抽象类。我想知道我需要做什么来解决这个问题,以便可以按任何顺序调用 setter。
最佳答案
如果您不想(或不能)按照 this answer 中的建议重写 ExtensionBuilder
类中的 withOne
方法, 你可以使用 recursively bounded generic type对于您的 build 者:
abstract static class Builder<T extends Data, B extends Builder<T, B>> {
private String one;
protected Builder() {
this.one = null;
}
public final B withOne(final String value) {
this.one = value;
return (B) this;
}
protected abstract T build();
}
然后,声明ExtensionBuilder
类如下:
public static final class ExtensionBuilder
extends Data.Builder<Extension, ExtensionBuilder>
这将允许您以任何顺序使用最具体的构建器方法,因为编译器现在知 Prop 体构建器的静态类型。
编辑:
正如 @Radiodef in the comments 指出的那样,还有一个替代方法,它包括在 Builder
类中声明一个 protected abstract B getThis()
方法:
abstract static class Builder<T extends Data, B extends Builder<T, B>> {
private String one;
protected Builder() {
this.one = null;
}
protected abstract B getThis();
public final B withOne(final String value) {
this.one = value;
return getThis(); // no need to cast now
}
protected abstract T build();
}
当然,在 ExtensionBuilder
中,您应该将其实现为:
@Override
protected ExtensionBuilder getThis() { return this; }
这是来源:http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ205
关于java - 如何定义构建器模式层次结构,其中可以按任何顺序调用 setter ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48429730/