web-dev-qa-db-ja.com

クラスコンストラクターは他のクラスのオブジェクトを作成する必要がありますか?

コンストラクターに、必要なクラスの新しいインスタンスを作成させるのと、新しいクラスに必要な参照を渡すのとでは、どちらが良いのでしょうか、それとも悪いのでしょうか?

つまり、基本的には次の違いです。

A classA = new A();
B classB = new B(classA);

また、クラスAをそのフィールド/プロパティに割り当てるクラスBコンストラクタがあります。

と比べて:

B classB = new B();

そして

public class B{
   A classA {private set; get;}
   //constructor
   public B(){
     classA = new A();
   }
}

後者の例は、作成および割り当て以降、単一の責任に違反しますか?プログラマーが知らないことをしているという点で、これはあまりにも多くの魔法ですか?コンストラクタはそれを行うべきですか?

2
WDUK

Aが実際に行っていること、およびBの存続期間中にAが果たす役割に依存すると思います。たとえば、Aが単なるArrayListまたはBの状態をカプセル化している他のオブジェクトである場合、BのコンストラクターでAのインスタンスを作成してもまったく問題ありません。

一方、AのインスタンスのライフサイクルがBによって管理されていない場合や、Aの実装を変更したい場合(テスト中など)、コンストラクタを介してインスタンスを挿入する必要があります。

this one のように、依存性注入をいつ使用するかに関する多くのリソースがあります。 これ のような既存のStackOverflow質問もあります。

9
Hero Wanders

コンストラクターは、定期的に他のオブジェクトを作成します。一部の言語では、それは避けられないものです。たとえば、C++では、コンストラクターが新しいオブジェクトのすべてのメンバーオブジェクトを構築します。

ですから、それ自体は良くも悪くもありません。それは意味論に依存します:

  • コンストラクターが、作成されたオブジェクトによって所有されていないオブジェクトを作成することは悪い習慣です。したがって、ABを存続させることを意図している場合、new B()は適切なオプションではありません。
  • 「サブ構造」が望ましくない依存関係を導入する場合(たとえば、サブオブジェクトが多態性であり、異なる専門化を持つ可能性がある場合)は、これも悪い習慣です。この場合、依存関係注入が優先されます(オブジェクトまたはファクトリーをパラメーターとして提供します)。
  • 最後に、サブ構築されたオブジェクトが構築されたオブジェクトへの参照を必要とする場合、それはひどい考えです(作成されたオブジェクトがまだ完全に構築されていないオブジェクトへの参照で何を行うかわからないため)。
3
Christophe

2番目のアプローチの主な問題は、テストが非常に難しいことです。

ClassAの特定の動作を検証するテストを作成する場合、それは常にClassBに依存しています。 ClassAのコンストラクターでClassBを作成した場合、それを制御することはできません。 ClassAがいくつかの条件付き作業を行うためにClassBのプロパティFooを読み取る場合、さまざまなケースをどのようにチェックしますか?テストをセットアップする簡単な方法はありません。つまり、Fooプロパティを必要な値に設定します。

代わりにClassBをClassAのコンストラクターに注入すると、突然、はるかに単純になります。テストでは、ClassBのインスタンスを作成し、Fooの値を指定し、ClassAのインスタンスを作成して、正しい動作を確認できます。テストが完了しました。他のFoo値について繰り返します...

このパターンは依存性注入と呼ばれ、他のアプローチよりも優先されるはずです。コンストラクターで直接クラスを構築する場合の依存関係は、副作用を引き起こし、テストを困難にするため、アンチパターンです。

1
selmaohneh