我正在尝试为一些构建器类创建一个抽象基类,这样我就可以轻松地在Builder实现之间重用代码。我希望我的构建器支持方法链接,因此方法必须返回最具体类型的“this”实例。我想我可以用泛型来做这件事。不幸的是,如果不使用不安全的操作,我就无法做到这一点。有可能吗?
我正在尝试它(以及它如何工作)的示例代码如下。我想避免在“foo()”中输入T(导致未经检查的警告),可以这样做吗?
public class Builders
{
public static void main( final String[] args )
{
new TheBuilder().foo().bar().build();
}
}
abstract class AbstractBuilder<T extends AbstractBuilder<?>>
{
public T foo()
{
// set some property
return (T) this;
}
}
class TheBuilder extends AbstractBuilder<TheBuilder>
{
public TheBuilder bar()
{
// set some other property
return this;
}
public Object build()
{
return new Object();
}
}
答案 0 :(得分:50)
您想在T
中将extends AbstractBuilder<T>
声明为AbstractBuilder
。
使用abstract protected
方法获取this
类型的T
。
abstract class AbstractBuilder<T extends AbstractBuilder<T>> {
protected abstract T getThis();
public T foo() {
// set some property
return getThis();
}
}
class TheBuilder extends AbstractBuilder<TheBuilder> {
@Override protected TheBuilder getThis() {
return this;
}
...
}
或者,删除泛型类型参数,依赖协变返回类型并使代码更清洁客户端(尽管通常它们将使用TheBuilder
而不是基类的大部分实现细节),如果使用实施更详细。
答案 1 :(得分:8)
一种替代方法是不使用泛型,而是使用覆盖:
abstract class AbstractBuilder
{
public AbstractBuilder foo()
{
// set some property
return this;
}
}
class TheBuilder extends AbstractBuilder
{
@Override public TheBuilder foo()
{
super.foo(); return this;
}
public TheBuilder bar()
{
// set some other property
return this;
}
public Object build()
{
return new Object();
}
}
答案 2 :(得分:0)
这应该有所帮助:
abstract class AbstractBuilder<T extends AbstractBuilder<?>>
{
public AbstractBuilder<T> foo()
{
// set some property
return (AbstractBuilder<T>) this;
}
abstract AbstractBuilder<T> bar();
abstract Object build();
}