静的ヘルパー関数を使用してコンストラクター引数を作成することは完全に正気のソリューションですが、これらの関数はそれぞれ正確に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; }})
イディオムを使用して引数を渡すことができます。
静的初期化ブロックで計算される静的変数を使用することは、真に静的なデータには意味がありますが、グローバル状態を回避するように注意する必要があります。初期化が非常に単純でない限り、初期化をテストできるようにするには、静的関数を使用してこれらの変数を初期化する必要があります。現在、静的メソッドを直接使用することの唯一の利点は、値が一度だけ計算され、すべての初期化で再利用されることです。
あなたの質問は、これらの初期化がより複雑になる可能性があることを示しているため、静的な初期化子ブロックを使用することは、テスト容易性が重要である場合、大きなノーノーです。(そうでない場合は、より緊急の問題があります。)