Builderの実装間でコードを簡単に再利用できるように、いくつかの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();
}
}
T
をAbstractBuilder
でextends AbstractBuilder<T>
として宣言します。
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つの代替方法は、ジェネリックを使用せず、オーバーライドを使用することです。
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();
}
}
これは役立つはずです:
abstract class AbstractBuilder<T extends AbstractBuilder<?>>
{
public AbstractBuilder<T> foo()
{
// set some property
return (AbstractBuilder<T>) this;
}
abstract AbstractBuilder<T> bar();
abstract Object build();
}