201

クラスをモデル化する場合、初期化の推奨方法は次のとおりです。

  1. コンストラクター、または
  2. ファクトリ メソッド

そして、それらのいずれかを使用するための考慮事項は何ですか?

特定の状況では、オブジェクトを構築できない場合に null を返すファクトリ メソッドを使用することを好みます。これでコードがすっきりします。コンストラクターから例外をスローするのとは対照的に、代替アクションを実行する前に、戻り値が null でないかどうかを簡単に確認できます。(個人的には例外は好きではありません)

たとえば、id 値を期待するクラスにコンストラクターがあるとします。コンストラクターはこの値を使用して、データベースからクラスを設定します。指定された ID を持つレコードが存在しない場合、コンストラクターは RecordNotFoundException をスローします。この場合、そのようなすべてのクラスの構築を try..catch ブロック内で囲む必要があります。

これとは対照的に、レコードが見つからない場合に null を返すクラスに静的ファクトリ メソッドを設定できます。

この場合、コンストラクターまたはファクトリーメソッドのどちらのアプローチが優れていますか?

4

10 に答える 10

241

それらが何であるか、なぜ私たちがそれらを持っているのかを自問してください。どちらもオブジェクトのインスタンスを作成するために存在します。

ElementarySchool school = new ElementarySchool();
ElementarySchool school = SchoolFactory.Construct(); // new ElementarySchool() inside

これまでのところ違いはありません。ここで、さまざまな学校の種類があり、ElementarySchool の使用から HighSchool (ElementarySchool から派生するか、ElementarySchool と同じインターフェイス ISchool を実装する) に切り替えたいとします。コードの変更は次のようになります。

HighSchool school = new HighSchool();
HighSchool school = SchoolFactory.Construct(); // new HighSchool() inside

インターフェースの場合、次のようになります。

ISchool school = new HighSchool();
ISchool school = SchoolFactory.Construct(); // new HighSchool() inside

このコードが複数の場所にある場合、ファクトリ メソッドを変更すると作業が完了するため、ファクトリ メソッドを使用する方がかなり安価であることがわかります (インターフェイスで 2 番目の例を使用する場合)。

そして、これが主な違いと利点です。複雑なクラス階層を扱い始め、そのような階層からクラスのインスタンスを動的に作成したい場合、次のコードが得られます。ファクトリ メソッドは、どの具象インスタンスをインスタンス化するかをメソッドに指示するパラメーターを受け取る場合があります。MyStudent クラスがあり、対応する ISchool オブジェクトをインスタンス化して、生徒がその学校のメンバーになるようにする必要があるとします。

ISchool school = SchoolFactory.ConstructForStudent(myStudent);

これで、さまざまな IStudent オブジェクトに対してどの ISchool オブジェクトをインスタンス化するかを決定するビジネス ロジックを含む、アプリ内の 1 つの場所ができました。

したがって、単純なクラス(値オブジェクトなど)の場合、コンストラクターは問題ありませんが(アプリケーションを過度に設計したくない場合)、複雑なクラス階層の場合はファクトリメソッドが推奨される方法です。

このようにして、4 冊の本のギャングからの最初の設計原則「実装ではなくインターフェイスへのプログラム」に従います。

于 2009-03-10T05:18:28.923 に答える
79

(アクセス権がある場合) を読む必要があります。効果的な Java 2 項目 1: コンストラクターの代わりに静的ファクトリ メソッドを検討してください。

静的ファクトリ メソッドの利点:

  1. 名前があります。
  2. 呼び出されるたびに新しいオブジェクトを作成する必要はありません。
  3. 戻り値の型の任意のサブタイプのオブジェクトを返すことができます。
  4. パラメータ化された型のインスタンスを作成する際の冗長性を軽減します。

静的ファクトリ メソッドの欠点:

  1. 静的ファクトリ メソッドのみを提供する場合、パブリック コンストラクターまたはプロテクト コンストラクターを持たないクラスはサブクラス化できません。
  2. それらは他の静的メソッドと容易に区別できません
于 2009-03-10T07:26:10.053 に答える
63

Gamma、Helm、Johnson、および Vlissides による Design Patterns: Elements of Reusable Object-Oriented Software の108 ページから。

ファクトリ メソッド パターンを使用する場合

  • クラスは、作成しなければならないオブジェクトのクラスを予測できません
  • クラスは、そのサブクラスが作成するオブジェクトを指定することを望んでいます
  • クラスがいくつかのヘルパー サブクラスの 1 つに責任を委任し、どのヘルパー サブクラスが委任されているかの知識をローカライズしたい
于 2009-03-10T04:43:27.213 に答える
35

デフォルトでは、理解しやすく書きやすいコンストラクターを優先する必要があります。ただし、クライアント コードで理解されるセマンティックな意味からオブジェクトの構築の詳細を切り離す必要がある場合は、ファクトリを使用することをお勧めします。

コンストラクターとファクトリーの違いは、変数と変数へのポインターに似ています。別のレベルの間接性がありますが、これは欠点です。しかし、別のレベルの柔軟性もあり、これは利点です。したがって、選択を行う際には、この費用対効果の分析を行うことをお勧めします。

于 2009-03-10T04:41:21.633 に答える
14

コンストラクターでは不可能な方法で、オブジェクトの作成に追加の制御が必要な場合にのみ、ファクトリを使用してください。

たとえば、ファクトリにはキャッシュの可能性があります。

ファクトリを使用するもう 1 つの方法は、構築するタイプがわからないシナリオです。このタイプの使用法は、各プラグインがベースクラスから派生するか、何らかのインターフェイスを実装する必要があるプラグイン ファクトリのシナリオでよく見られます。ファクトリは、基本クラスから派生するクラスまたはインターフェイスを実装するクラスのインスタンスを作成します。

于 2009-03-10T07:12:38.323 に答える
11

「Effective Java」、第 2 版、項目 1 からの引用: コンストラクターの代わりに静的ファクトリー メソッドを検討してください。5:

静的ファクトリ メソッドは、デザイン パターン [Gamma95、p. 107] のファクトリ メソッド パターンと同じではないことに注意してください。この項目で説明されている静的ファクトリ メソッドには、デザイン パターンに直接相当するものはありません。」

于 2010-11-27T22:50:50.913 に答える
8

CAD/CAMアプリケーションからの具体例。

コンストラクターを使用して、切断パスを作成します。これは、切断するパスを定義する一連の線と円弧です。一連の線と円弧は異なる場合があり、異なる座標を持つ場合がありますが、リストをコンストラクターに渡すことで簡単に処理できます。

工場を使って形を作ります。シェイプクラスはありますが、シェイプのタイプに応じて各シェイプの設定が異なるためです。ユーザーが選択するまで、初期化する形状はわかりません。

于 2009-03-10T12:30:42.350 に答える
5

たとえば、id 値を期待するクラスにコンストラクターがあるとします。コンストラクターはこの値を使用して、データベースからクラスを設定します。

このプロセスは、必ずコンストラクターの外にある必要があります。

  1. コンストラクターはデータベースにアクセスしてはなりません。

  2. コンストラクターのタスクと理由は、データ メンバーを初期化し、コンストラクターに渡された値を使用してクラス不変を確立することです。

  3. それ以外の場合は、静的ファクトリ メソッドを使用するか、より複雑なケースでは別のファクトリまたはビルダークラスを使用することをお勧めします。

Microsoft からのいくつかのコンストラクター ガイドライン:

コンストラクターで最小限の作業を行います。コンストラクターは、コンストラクターのパラメーターを取得する以外に多くの作業を行うべきではありません。他の処理のコストは、必要になるまで延期する必要があります。

目的の操作のセマンティクスが新しいインスタンスの構築に直接マップされない場合は、コンストラクターの代わりに静的ファクトリ メソッドの使用を検討してください。

于 2015-09-22T10:17:06.157 に答える