web-dev-qa-db-ja.com

安全でない操作を行わずに、メソッドチェーンを使用してJavaに抽象ビルダークラスを含めることはできますか?

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();
   }
}
25
Patrick Huy

TAbstractBuilderextends AbstractBuilder<T>として宣言します。

abstract protectedメソッドを使用して、タイプthisTを取得します。

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を使用します)。詳細。

53

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();
   }
}
8
Jason S

これは役立つはずです:

abstract class AbstractBuilder<T extends AbstractBuilder<?>>
{
   public AbstractBuilder<T> foo()
   {
      // set some property
      return (AbstractBuilder<T>) this;
   }

   abstract AbstractBuilder<T> bar();
   abstract Object build();
}
0
Mike Thomsen