2

流暢なインターフェースでビルダーを実装したいと思います。

要件

物事をより困難にするために、2つの追加要件があります。

  1. 返されたオブジェクトを不変にして、次のように使用できるようにし、インターフェイスを派生インターフェイスで拡張できるようにします。

    ConcreteBuilder b1 = builder().setValue(1);
    ConcreteBuilder b2 = b1.setValue(2);
    
    ComplexObject o1 = b1.build();
    o1.getValue(); // should return 1
    
    ComplexObject o2 = b2.build();
    o2.getValue(); // should return 2
    

    最初に議論の余地のある問題:ビルダーは、上記のセマンティクスを持つように不変である必要がありますか?( Jonathanが、セットを含む不変クラスの不変ビルダーを作成する方法について簡単にコメントしていますか? )

  2. ビルダーインターフェイスは拡張可能である必要があります。

    interface Builder<T extends Builder<T>> {
         T setValue(int v);
    }
    
    interfacte BuilderEx<T extends BuilderEx<T>> {
         T someOtherOpp();
    }
    

    (Eamonn McManus 1で説明されているように、自己参照ジェネリックを使用します)

実装

最初の要件を満たすために、AbstractBuilderの実装は、セットを含む不変クラスの不変ビルダーを作成する方法の実装に似ています。:

class AbstractBuilder<T extends Builder<T>> implements Builder<T> {
    T setValue(final int v) {
        return castToConcrete(new AbstractBuilder<T>() {
            // with build() overridden to use v
        }
    }
}

castToConcreteself()1およびgetThis()2に類似している必要があります:Builder<T>ConcreteBuilderまたはConcreteBuilderExに依存して変換しTます。問題は、どのように実装するかですcastToConcrete

Builderメソッドは新しいインスタンスを作成するため、オーバーライドするメソッドは機能getThisConcreteBuilderません。のコンストラクターに提供され、フィールドに格納されている「ファンクター」3を使用すると、へAbstractBuilderの変換が可能になります。次のフィールドを追加します(Guavaライブラリ3を使用して:Builder<T>TAbstractBuilder

Function<Builder<T>, T> castToConcrete;

問題

私の現在の実装はcastToConcrete非常に醜いです:

  1. それは上のif-else木ですinstanceof
  2. のすべてのメソッドを定義する必要があるラッパークラスではinput instanceof Builderなく、メソッドをに転送し、他のメソッドに対してデフォルトまたはnil操作を実行する場合。input instanceof BuilderExBuilderExBuilderinput
  3. の実際のインスタンスではなく、 (これが機能することを期待して)匿名のサブクラスのインスタンスであるにもかかわらず、input instanceof BuilderEx入力をキャストする場合ConcreteBuilderExinputConcreteBuilderExAbstractBuilderEx[OPによる編集]機能しません:すべてのインターフェイスにラッパーが必要です[/ edit]

これを行うためのより良い/よりクリーンな方法は何ですか?

4

1 に答える 1

3

クリーンな方法は、を使用せず、AbstractBuilderビルドする必要があるタイプごとに特定のビルダーを作成することです。ビルダー メソッドを読み取り可能にし、構築しようとしているオブジェクトに合わせてカスタマイズすることで、流暢なインターフェイスを取得します。多くのビルダーを作成する必要がある場合は、コード生成を使用できますが、メソッドは適切に設計されていません。

于 2012-05-16T13:44:01.843 に答える