依存性注入のスタイルの実際の違いは何ですか?


12

依存性注入は初めてなので、アプリケーションでどのスタイルを使用すべきかについていくつか質問があります。Martin FowlerによるInversion of Control ContainersとDependency Injectionパターンを読んだばかりですが、コンストラクター、セッター、インターフェースインジェクションの実際の違いを理解することはできません。

どちらか一方を使用する理由は、コードのクリーニングおよび/または明快さの問題だけであるように思えます。違いはなんですか?あるものを他のものよりも使用することの強力な長所または短所はありますか、それとも前に述べたとおりですか?

私の意見では、コンストラクター注入はすべての中で最も直感的であり、インターフェース注入は最も少ないです。一方、セッターインジェクションは中期ですが、最初にインジェクトした依存関係オブジェクトのインスタンスを変更できるはずですか?このスタイルの注入は、依存関係を必要とするオブジェクトが常に注入されることを保証しますか?私はそうは思わないが、私が間違っているなら私を修正してください。


他に何を見つけたか、途中で読んだかわからない。ここここで似たようなスレッドを見つけまし。私は新しいので、あなたが得るかもしれない答えに興味があります:)

@ user1766760あなたはここで私を助けるべきです、私の質問は閉じられるように投票されており、もう2つの投票が完了しました!!! 質問に何か投票してください。閉鎖を避けるために何ができるかわかりません。
ecampver

えーと...私は自分自身が初めてなので、どうすれば手伝うことができるのか、なぜ閉鎖するのに投票されているのか分かりません(兆候は見られませんか?)。私が推測に挑戦した場合、おそらくそれは特定のプログラミングの質問ではなく、より多くの議論ですか?

質問を少し広げてください。依存性注入は、「制御の反転」の一形態です。選択肢があります。便利ですが、悪用の代替手段としては、たとえばサービスロケーションがあります。
イアン

回答:


12

コンストラクターインジェクションには、依存関係を明示的に示し、クライアントにインスタンスの提供を強制するという利点があります。また、クライアントが後でインスタンスを変更できないことも保証できます。1つの(可能性のある)欠点は、コンストラクターにパラメーターを追加する必要があることです。

Setter Injectionには、コンストラクターにパラメーターを追加する必要がないという利点があります。また、クライアントがインスタンスを設定する必要もありません。これは、オプションの依存関係に役立ちます。これは、たとえばデフォルトで実際のデータリポジトリを作成するクラスが必要な場合にも役立ちます。テストでは、セッターを使用してテストインスタンスに置き換えることができます。

インターフェイスインジェクションは、私が知る限り、セッターインジェクションと大差ありません。どちらの場合も、(オプションで)後で変更できる依存関係を設定しています。

最終的に、それは好みの問題であり、依存関係が必要かどうかです。個人的には、コンストラクター注入をほぼ排他的に使用しています。クライアントにコンストラクターでインスタンスを提供させることにより、クラスの依存関係を明示的にすることが好きです。また、クライアントは事後にインスタンスを変更できないことも気に入っています。

多くの場合、2つの別個の実装を渡す唯一の理由はテストのためです。本番環境ではDataRepository、に合格するかもしれませんが、テストでは、に合格しますFakeDataRepository。この場合、通常、2つのコンストラクターを提供します。1つはパラメーターなし、もう1つはを受け入れるコンストラクターですIDataRepository。次に、パラメーターのないコンストラクターで、2番目のコンストラクターへの呼び出しをチェーンし、aを渡しnew DataRepository()ます。

C#の例を次に示します。


public class Foo
{
  private readonly IDataRepository dataRepository;

  public Foo() : this(new DataRepository())
  {
  }

  public Foo(IDataRespository dataRepository)
  {
    this.dataRepository = dataRepository;
  }
}

これは、Poor Man's Dependency Injectionとして知られています。実稼働クライアントコードでは、次のようなステートメントを繰り返して繰り返す必要がないため、気に入っています。

var foo = new Foo(new DataRepository());
ただし、テスト用に別の実装を渡すことはできます。Poor ManのDIでは依存関係をハードコーディングしていることがわかりますが、テストにはほとんどDIを使用しているので、それは受け入れられます。


おかげで、それは私が理解していることに非常に近いですが、コンストラクタインジェクションを使用できないシナリオはありますか?
ecampver

1
オプションの依存関係にコンストラクター注入を使用することはおそらくないでしょう。それを使用しない他の理由は考えられません。
ジューレット

特に、プロパティセッターインジェクションを使用して、多数の値を含むいくつかの構成クラスを設定します。私はそれを他のどこでも使用しません。単一の責任ルールの違反である可能性が十分にあるため、オプションのパラメーターを主張することについて、私はいつも少し疑っています。もちろん、ルールは破られることを意図しているので
イアン

@jhewlett-それは素晴らしいです、私はソリューションを複雑にしないユニットテストのための良いシンプルなスタブテクニックを探していました-そして、私はこれだと思います:)
ロックラン

2

コンストラクターとセッターインジェクションの違いは、すでに上で十分に説明されているので、これ以上詳しく説明しません。

インターフェース注入は、それを使用するオブジェクトの初期化中ではなく、使用時に依存関係を決定できるため、便利な注入のより高度な形式です。これにより、多くの便利なオプションが可能になります。

  • 依存関係のスコープは、注入されるオブジェクトとは異なる場合があります。たとえば、インターフェイスインジェクションを使用して、ユーザーセッションごとまたはスレッドごとに存在するオブジェクトをグローバルシングルトンに提供できます。オブジェクトが依存関係を必要とするたびに、フレームワークが提供するgetterメソッドを呼び出します。これは、呼び出される状況に応じて異なる結果を返す可能性があります。

  • 遅延初期化が可能です-使用される直前まで依存関係を初期化する必要はありません

  • 依存関係が存在する場合はキャッシュされたコピーからロードでき、存在しない場合は再初期化できます(SoftReferenceJavaでa を使用するなど)。

このような明らかに高度な手法には欠点があります。この場合の主な問題は、コードがあまり明確にならないことです(コードで使用されるクラスは抽象的になり、それらの明確な具体的な実装はありません。依存性注入フレームワーク上(もちろん、オブジェクトを手動でインスタンス化することは可能ですが、他の注入スタイルよりも困難です)。

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