Mar*_*iam 7 java generics abstract-class builder
考虑带有抽象Builder的抽象Data类:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
该类已扩展,其中还包括自己的扩展构建器:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
Extension对象从两个类中获取所有方法.但是,调用setter方法的顺序很重要.还行吧:
Extension one = Extension.ExtensionBuilder
.newInstance()
.withTwo("two")
.withOne("one")
.build();
Run Code Online (Sandbox Code Playgroud)
这会产生编译错误:
Extension two = Extension.ExtensionBuilder
.newInstance()
.withOne("one")
.withTwo("two")
.build();
Run Code Online (Sandbox Code Playgroud)
我知道为什么,withOne()setter将Builder对象的类型从具体类向下转换为抽象类.我想知道我需要做些什么来解决这个问题,因此可以按任何顺序调用setter.
如果您不想(或不能)按照此答案withOne
中的建议重写类中的方法,则可以为您的构建器使用递归有界泛型类型:ExtensionBuilder
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();
}
Run Code Online (Sandbox Code Playgroud)
然后,声明该类ExtensionBuilder
如下:
public static final class ExtensionBuilder
extends Data.Builder<Extension, ExtensionBuilder>
Run Code Online (Sandbox Code Playgroud)
这将允许您以任何顺序使用最具体的构建器的方法,因为编译器现在知道具体构建器的静态类型。
编辑:正如@Radiodef 在注释中
指出的,还有一种替代方法,其中包括protected abstract B getThis()
在类中声明一个方法Builder
:
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();
}
Run Code Online (Sandbox Code Playgroud)
当然,ExtensionBuilder
您应该将其实现为:
@Override
protected ExtensionBuilder getThis() { return this; }
Run Code Online (Sandbox Code Playgroud)
这是来源:http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ205
归档时间: |
|
查看次数: |
179 次 |
最近记录: |