Static Createメソッド—コンストラクターと比較した賛否両論


11

コンストラクターに対して静的オブジェクト作成メソッドを使用することの長所と短所は何ですか?

class Foo {
  private Foo(object arg) { }

  public static Foo Create(object arg) {
    if (!ValidateParam(arg)) { return null; }
    return new Foo(arg);
  }
}

私が考えることができることはほとんどありません:

長所:

  • 例外をスローする代わりにnullを返します(名前を付けますTryCreate)。これにより、クライアント側でコードがより簡潔でクリーンになります。クライアントがコンストラクターの失敗を期待することはほとんどありません。
  • 明確なセマンティクスでさまざまな種類のオブジェクトを作成します。たとえばCreatFromName(String name)CreateFromCsvLine(String csvLine)
  • 必要に応じて、キャッシュされたオブジェクト、または派生した実装を返すことができます。

短所:

  • 発見しにくく、コードのスキミングがより困難です。
  • シリアル化やリフレクションなどの一部のパターンはより困難です(例Activator<Foo>.CreateInstance()

1
遅いです。とにかくヌル参照を処理する必要があります。
アミールRezaei

1
@Amir Handling nullは(Foo x = Foo.TryCreate(); if (x == null) { ... })です。ctor例外の処理は(Foo x; try { x = new Foo(); } catch (SomeException e) { ... })です。通常のメソッドを呼び出すとき、エラーコードよりも例外を好みますが、オブジェクトの作成でTryCreateはクリーンに見えます。
dbkk

検証で型チェックを行いますか?
アミールRezaei

2番目のProの「明確なセマンティクスでさまざまな種類のオブジェクトを作成します。たとえば、CreatFromName(String name)とCreateFromCsvLine(String csvLine)」では、メソッド名で要件を表現するよりも、作成NameしてCsvLineタイプする方がよい場合があります。これにより、Createをオーバーロードできます。両方に文字列を使用することは、「原始的な強迫観念」とみなすことができます(既知のパフォーマンス上の理由でこの選択を行わなかったと仮定)。これを探る楽しい方法については、Object Calisthenicsご覧ください。
ベンタイロルク

回答:


7

静的な「作成者」の最大の欠点は、おそらく継承を制限することです。あなたやあなたのライブラリーの利用者があなたからクラスを派生した場合はFoo、その後、Foo::Create()ほとんど役に立たないとなります。そこで定義されたすべてのロジックは、継承されたで再度書き換える必要がありますCreate()

妥協案を提案します:決して失敗/スローしない単純なオブジェクト初期化ロジックを使用してコンストラクターを定義し、次にキャッシュ、代替構築などを使用して作成者を定義します。 。


1
ほとんどのクラスは継承されるように設計されていないため、実際には問題になりません(したがって、封印された/最終的なものでなければなりません)。後でクラスを継承まで開くことが判明した場合、いつでも初期化ロジックを保護されたコンストラクターに移動できます。
ドーバル

7

CreateはFactoryメソッドです。これが必要だと感じたら、Factoryパターンを実装し、オブジェクトと実装クラスを作成するためのコントラクトを表すインターフェイスを定義し、必要な場所にインジェクトします。これにより、作成責任をクラスの外に移動する利点は保持されますが、クラスコンストラクターの外部でオブジェクト作成を実行することの制限が回避されます(少なくともより明確になります)。

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