大きな静的初期化子はコードの匂いですか?


8

SimpleExpandableListAdapterAndroidで拡張しています。Androidのアダプターは、コンストラクターにかなり複雑な引数が多数あり、セッターやビルダーがないため、あまりうまく実装されていないと思います。私のクラスでは、これらの引数のほとんどは呼び出し元のクラスに依存していないため、内部的に構築したいと思います。ただし、引数はネストされたListsであり、プログラムで構築する必要がある整数と文字列の配列です。

superコンストラクタの前に何もsuper呼び出すことができず、呼び出しが戻る前にインスタンスメソッドを呼び出すことができないため、現在、呼び出しから呼び出す静的メソッドがいくつかありsuperます。

super(getContext(), initGroupData(), groupLayout, initGroupFrom(), initGroupTo(),
        initChildData(), childLayout, initChildFrom(), initChildTo());

これを処理する方法は3つあります。今と同じように静的メソッドを呼び出す、おそらくこれらの同じメソッドを呼び出して静的変数を初期化して静的変数を初期化する大きな静的イニシャライザを使用するsuperか、これらのメソッドをすべてビルダーにカプセル化します。

今はビルダーに傾いていると思いますが、これを処理するためのより良い方法があるかどうか疑問に思っています。


1
ファクトリメソッド/関数についてはどうですか?
パウロEbermann

回答:


9

静的ヘルパー関数を使用してコンストラクター引数を作成することは完全に正気のソリューションですが、これらの関数はそれぞれ正確に1つの引数を生成する必要があり、互いに通信できないため、実行できる操作が制限されます。

インターフェースConstructor(A, B, C)をより使いやすいインターフェースに適合させる最も一般的なケースでConstructor(X, Y)は、プライベートヘルパーコンストラクターを定義して、プライベートArgumentObjectを取得し、既存のコンストラクターにチェーンできます。次に、より使いやすいコンストラクターが静的ヘルパー関数を介してヘルパーコンストラクターにチェーンし、引数オブジェクトを作成します。

class Constructor {
  // constructor you want to wrap
  public Constructor(A a, B b, C c) { ... }
  // better constructor you are defining
  public Constructor(X x, Y y) { this(createArgumentObject(x, y)); }
  // helper constructor using an ArgumentObject
  private Constructor(ArgumentObject ao) { this(ao.a, ao.b, ao.c); }
  // helper to create the argument object
  private static ArgumentObject createArgumentObject(X x, Y y) { ... }
  private static class ArgumentObject { ... }
}

同じクラス(C ++ 03など)内にチェーンコンストラクターがない言語では、ヘルパーコンストラクターの中間サブクラスを定義する必要があります。

ただし、この手法は、コンストラクター引数での静的関数の使用を一般化したものにすぎません。あなたが提案した他の解決策にはさまざまな欠点があります。そのため、それらを好む十分な理由がない限り、それらを避けます。

  • 優れたビルダーを実装するには、ほとんど価値がないために多大な労力が必要です。新しいコンストラクターが十分に単純であれば、ビルダーなしで実行できます。ラップしているクラスが確実な検証を実行すると仮定すると、引数オブジェクトをパブリックにして、Constructor(new Constructor.Arguments {{ foo = 42; bar = baz; }})イディオムを使用して引数を渡すことができます。

  • 静的初期化ブロックで計算される静的変数を使用することは、真に静的なデータには意味がありますが、グローバル状態を回避するように注意する必要があります。初期化が非常に単純でない限り、初期化をテストできるようにするには、静的関数を使用してこれらの変数を初期化する必要があります。現在、静的メソッドを直接使用することの唯一の利点は、値が一度だけ計算され、すべての初期化で再利用されることです。

    あなたの質問は、これらの初期化がより複雑になる可能性があることを示しているため、静的な初期化子ブロックを使用することは、テスト容易性が重要である場合、大きなノーノーです。(そうでない場合は、より緊急の問題があります。)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.