it-swarm-ja.com

依存性注入とは何ですか?

依存性注入 についての具体的な質問と一緒に、いくつかの質問がすでに投稿されています。しかしながら、

依存性注入とは何ですか。また、いつ/なぜそれを使用すべきか、または使用すべきではありませんか。

2874
AR.

基本的には、オブジェクトに依存関係を作成させたり、ファクトリオブジェクトに依存関係を作成させるのではなく、必要な依存関係を外部にオブジェクトに渡して、他の人の問題にします。この「誰か」は、依存関係グラフのさらに上位にあるオブジェクト、または依存関係グラフを作成する依存関係インジェクタ(フレームワーク)のいずれかです。ここで使用している依存関係は、現在のオブジェクトが参照を保持する必要があるその他のオブジェクトです。

依存性注入の主な利点の1つは、テストをずっと簡単にできることです。コンストラクタ内で次のような動作をするオブジェクトがあるとします。

public SomeClass() {
    myObject = Factory.getObject();
}

特にSomeClassが複雑なディスクまたはネットワークアクセスを行うものである場合は、myObject上でいくつかの単体テストを実行するだけでよい場合、これは面倒になることがあります。それで今、あなたはモザイクmyObjectだけでなく、どういうわけかファクトリコールを傍受しているのを見ています。ハード。代わりに、オブジェクトをコンストラクタの引数として渡します。これで問題は別の場所に移動しましたが、テストははるかに簡単になります。ダミーのmyObjectを作成してそれを渡すだけです。コンストラクタは次のようになります。

public SomeClass (MyClass myObject) {
    this.myObject = myObject;
}

これは、コンストラクタによる依存性注入の1つのスタイルです。いくつかのメカニズムが可能です。 

  • コメントで述べたように、一般的な代替案の1つは、何もしないコンストラクタを定義し、依存関係をプロパティセッター(h/t @MikeVella)を介して注入することです。 
  • Martin Fowler は、3番目の選択肢(h/t @MarcDix)を文書化しています。そこでは、クラスは注入したい依存関係のためのインターフェースを明示的に実装しています。

依存性注入を使用しない場合(コンストラクタなどであまりにも多くの作業を行うクラスなど)、単体テストでコンポーネントを分離することははるかに困難になる傾向があります。 

2013年に私がこの答えを書いたとき、これは Google Testing Blog の主要なテーマでした。ランタイム設計に特別な柔軟性を常に必要とするわけではないため(たとえば、サービスロケーターや類似のパターンなど)、これは私にとって最大の利点ですが、テスト中にクラスを分離できる必要があることがよくあります。

1764
wds

私がこれまで見つけた最高の定義は James Shoreによるものです : 

「依存注射」とは、5セントの概念を表す25ドルの用語です。 [...] 依存性注入はオブジェクトにそのインスタンス変数を与えることを意味します。 [...].

Martin Fowlerによる記事 もありますが、これも役に立ちます。

依存性注入は、基本的に、オブジェクト自体を構築するのではなく、オブジェクトが必要とするオブジェクト(その依存関係)を提供することです。依存関係をモックアップしたりスタブアウトしたりすることができるため、テストに非常に便利な手法です。

依存関係は、さまざまな方法(コンストラクター注入やセッター注入など)によってオブジェクトに注入することができます。そのためには、特殊な依存性注入フレームワーク(Springなど)を使用することもできますが、それらは必須ではありません。これらのフレームワークに依存性注入をする必要はありません。オブジェクト(依存関係)を明示的にインスタンス化して渡すことは、フレームワークによるインジェクションと同じくらい良いインジェクションです。

2167
Thiago Arrais

この面白い例を 疎結合の観点から見つけました

どのようなアプリケーションでも、互いに連携して有用なものを実行するための多数のオブジェクトで構成されています。伝統的に、各オブジェクトは、それが協働する依存オブジェクト(依存関係)へのそれ自身の参照を取得する責任がある。これは密結合クラスとテストが難しいコードにつながります。

たとえば、Carオブジェクトを考えます。

Carは実行する車輪、エンジン、燃料、バッテリーなどに依存します。伝統的に私達はCarオブジェクトの定義と共にそのような依存オブジェクトのブランドを定義します。

依存性注入なし(DI):

class Car{
  private Wheel wh = new NepaliRubberWheel();
  private Battery bt = new ExcideBattery();

  //The rest
}

ここでは、Car object が依存オブジェクトの作成を担当しています。

最初のNepaliRubberWheel()パンクチャの後に依存オブジェクトの型を変更したい場合(Wheelなど)新しい依存関係をChineseRubberWheel()と指定してCarオブジェクトを再作成する必要がありますが、Car製造元のみが可能です。

それではDependency Injectionは何のために私たちをしていますか?

依存性注入を使用すると、コンパイル時(自動車製造時)ではなく実行時にオブジェクトに依存関係が与えられます。。これで、必要に応じてWheelを変更できるようになりました。ここでは、実行時にdependencywheel)をCarに挿入できます。

依存性注入を使用した後:

ここでは、実行時に 注入 the 依存関係 (Wheel and Battery)になります。したがって、用語は依存性注入です。 

class Car{
  private Wheel wh = [Inject an Instance of Wheel (dependency of car) at runtime]
  private Battery bt = [Inject an Instance of Battery (dependency of car) at runtime]
  Car(Wheel wh,Battery bt) {
      this.wh = wh;
      this.bt = bt;
  }
  //Or we can have setters
  void setWheel(Wheel wh) {
      this.wh = wh;
  }
}

出典:_(依存性注入を理解する

554
gtiwari333

依存性注入は、オブジェクトを内部的に構築するのではなく、他のコードからオブジェクトのインスタンスを受け取る方法でオブジェクトを設計する方法です。これは、オブジェクトが必要とするインターフェースを実装しているすべてのオブジェクトを、コードを変更せずに代用できることを意味します。これにより、テストが簡単になり、デカップリングが向上します。

たとえば、次の句を検討してください。

public class PersonService {
  public void addManager( Person employee, Person newManager ) { ... }
  public void removeManager( Person employee, Person oldManager ) { ... }
  public Group getGroupByManager( Person manager ) { ... }
}

public class GroupMembershipService() {
  public void addPersonToGroup( Person person, Group group ) { ... }
  public void removePersonFromGroup( Person person, Group group ) { ... }
} 

この例では、PersonService::addManagerおよびPersonService::removeManagerの実装は、その作業を行うためにGroupMembershipServicename__のインスタンスを必要とします。 Dependency Injectionがない場合、これを行うための従来の方法は、GroupMembershipServicename__のコンストラクターに新しいPersonServicename__をインスタンス化し、そのインスタンス属性を両方の関数で使用することです。ただし、GroupMembershipServicename__のコンストラクタに必要なものが複数ある場合、またはさらに悪いことに、GroupMembershipServicename__で呼び出す必要がある初期化「セッター」がある場合、コードはかなり速く成長し、PersonServicename__はGroupMembershipServicename__だけではなくなりますGroupMembershipServicename__が依存する他のすべてのものも。さらに、GroupMembershipServicename__へのリンケージはPersonServicename__にハードコードされているため、テスト目的でGroupMembershipServicename__を「ダミーアップ」したり、アプリケーションのさまざまな部分でストラテジーパターンを使用することはできません。 

依存性注入では、GroupMembershipServicename__内でPersonServicename__をインスタンス化する代わりに、それをPersonServicename__コンストラクターに渡すか、またはProperty(getterおよびsetter)を追加してそのローカルインスタンスを設定します。これは、あなたのPersonServicename__がGroupMembershipServicename__を作成する方法についてもはや心配する必要がなく、それが与えられたものを単に受け入れ、そしてそれらと共に働くことを意味します。これはまた、GroupMembershipServicename__のサブクラスである、またはGroupMembershipServicename__インターフェースを実装するものはすべてPersonServicename__に「注入」でき、PersonServicename__はその変更について知る必要がないことを意味します。

241
Adam Ness

受け入れられた答えは良いものです - しかし、私はDIがコードの中でハードコードされた定数を避ける古典的なものと非常によく似ていることをこれに加えたいと思います。 

データベース名のような定数を使うときは、それをコードの内側からある設定ファイルにすばやく移動し、その値を含む変数を必要な場所に渡します。その理由は、これらの定数は通常、他のコードよりも頻繁に変更されるためです。たとえば、テストデータベースでコードをテストしたい場合です。 

オブジェクト指向プログラミングの世界では、DIはこれに似ています。定数リテラルの代わりにそこにある値はオブジェクト全体ですが、それらを作成するコードをクラスコードから移動する理由は似ています - オブジェクトはそれらを使用するコードよりも頻繁に変更されます。そのような変更が必要とされる1つの重要なケースはテストです。

155
zby

Car および Engine クラスを使用した簡単な例を試してみましょう。少なくとも今のところは、どの車にもエンジンが必要です。そのため、以下では依存性注入なしでコードがどのように見えるかを説明します。

public class Car
{
    public Car()
    {
        GasEngine engine = new GasEngine();
        engine.Start();
    }
}

public class GasEngine
{
    public void Start()
    {
        Console.WriteLine("I use gas as my fuel!");
    }
}

Carクラスをインスタンス化するために、次のコードを使います。

Car car = new Car();

このコードの問題は、GasEngineと密接に関連しており、それをElectricityEngineに変更する場合は、Carクラスを書き直す必要があります。そして、アプリケーションが大きくなればなるほど、新しいタイプのエンジンを追加して使用しなければならなくなる問題や頭痛の種が増えます。 

言い換えれば、このアプローチでは、私たちの高レベルのCarクラスは、SOLIDのDependency Inversion Principle(DIP)に違反する低レベルのGasEngineクラスに依存しています。 DIPは、具体的なクラスではなく抽象化に頼るべきだと示唆しています。これを満たすために、IEngineインターフェースを導入し、以下のようにコードを書き換えます。

    public interface IEngine
    {
        void Start();
    }

    public class GasEngine : IEngine
    {
        public void Start()
        {
            Console.WriteLine("I use gas as my fuel!");
        }
    }

    public class ElectricityEngine : IEngine
    {
        public void Start()
        {
            Console.WriteLine("I am electrocar");
        }
    }

    public class Car
    {
        private readonly IEngine _engine;
        public Car(IEngine engine)
        {
            _engine = engine;
        }

        public void Run()
        {
            _engine.Start();
        }
    }

現在、私たちのCarクラスは、エンジンの特定の実装ではなく、IEngineインターフェースのみに依存しています。 今、唯一のトリックは、どのようにしてCarのインスタンスを作成し、それにGasEngineまたはElectricityEngineのような実際の具体的なEngineクラスを与えるかです。 依存性注入 が入ってくるところです。 

   Car gasCar = new Car(new GasEngine());
   gasCar.Run();
   Car electroCar = new Car(new ElectricityEngine());
   electroCar.Run();

ここでは基本的にCarコンストラクターに依存関係(Engineインスタンス)を注入(渡し)します。それで今我々のクラスはオブジェクトとそれらの依存関係の間の疎結合を持っています、そして我々はCarクラスを変えることなしに新しいタイプのエンジンを簡単に加えることができます。

Dependency Injection の主な利点 - /クラスはより緩やかに結合されています、なぜならそれらはハードコーディングされた依存関係を持っていないからです。これは、先に述べた依存性反転原理に従います。特定の実装を参照する代わりに、クラスはクラスが構築されたときにそれらに提供される抽象化(通常は interfaces )を要求します。

つまり、 依存性注入 は、オブジェクトとそれらの依存関係の間の疎結合を達成するための単なるテクニックです。クラスが必要とする依存関係を直接インスタンス化するのではなくそのアクションを実行すると、依存関係はコンストラクター注入によってクラスに(ほとんどの場合)提供されます。

また、多くの依存関係がある場合は、すべての依存関係に対してどのインターフェイスをどの具体的な実装にマッピングする必要があるかを示すことができるInversion of Control(IoC)コンテナを使用することをお勧めします。私たちの目的たとえば、IoCコンテナのマッピングで、 IEngine 依存関係を GasEngine クラスにマッピングし、IoCコンテナに Car クラスのインスタンスを要求するように指定できます。それは自動的に Gas 依存関係を渡された Car クラスを構築するでしょう。 

更新日: /最近Julie LermanからEF Coreについてのコースを見て、またDIについての彼女の短い定義が好きだった。

依存性注入は、それらのクラスがそれらのオブジェクトに対して責任を負うことを強いることなく、アプリケーションがそれらを必要とするクラスにその場でオブジェクトを注入することを可能にするパターンです。それはあなたのコードがより疎結合されることを可能にし、Entity Framework Coreはこれと同じサービスシステムにプラグインします。

103
user2771704

あなたが釣りに行きたいと想像してみましょう:

  • 依存性注入なしで、あなたは自分自身ですべての世話をする必要があります。ボートを探す、釣り竿を買う、餌を探すなどが必要です。もちろん可能ですが、それはあなたに多くの責任を負わせます。ソフトウェアの用語では、それはあなたがこれらすべてのもののためにルックアップを実行しなければならないことを意味します。

  • 依存性注入では、他の誰かがすべての準備を引き受け、必要な機器を利用できるようにします。あなたはボート、釣り竿、そして餌を受け取ります(「注入されます」)。

102
Olivier Liechti

これ Dependency Injection および Dependency Injection Container についての最も簡単な説明です。

依存性注入なし

  • アプリケーションにはFoo(例えばコントローラ)が必要です。
  • アプリケーションがFooを作成
  • アプリケーションはFoo を呼び出します。
    • FooはBar(例えばサービス)を必要とします。
    • FooはBarを作ります
    • FooはBar を呼び出します
      • BarにはBim(サービス、リポジトリ、…)が必要です。
      • バーはビムを作成します
      • バーは何かをする

依存性注入あり

  • アプリケーションにはFooが必要で、BarにはBimが必要です。
  • アプリケーションがBimを作成する
  • アプリケーションはBarを作成してBimを提供します
  • アプリケーションがFooを作成してBarを付与する
  • アプリケーションはFoo を呼び出します。
    • FooはBar を呼び出します
      • バーは何かをする

依存性注入コンテナーの使用

  • アプリケーションにはFooが必要です。
  • アプリケーションはコンテナからFooを取得するので、
    • コンテナーはビムを作成します
    • コンテナはBarを作成してBimを与えます
    • コンテナはFooを作成してBarを与えます
  • アプリケーションはFoo を呼び出します。
    • FooはBar を呼び出します
      • バーは何かをする

依存性注入 依存性注入コンテナ は別物です。

  • 依存性注入は、より良いコードを書くための方法です。
  • dIコンテナは依存関係を注入するのに役立つツールです。

あなたは依存性注入をするためにコンテナを必要としません。しかし容器はあなたを助けることができます。

86
Trix

「依存性注入」とは、単にパラメータ化されたコンストラクタやパブリックセッタを使うという意味ではありませんか?

James Shoreの記事は比較のために次の例を示しています

依存性注入のないコンストラクタ

public class Example { 
  private DatabaseThingie myDatabase; 

  public Example() { 
    myDatabase = new DatabaseThingie(); 
  } 

  public void doStuff() { 
    ... 
    myDatabase.getData(); 
    ... 
  } 
} 

依存性注入のあるコンストラクタ

public class Example { 
  private DatabaseThingie myDatabase; 

  public Example(DatabaseThingie useThisDatabaseInstead) { 
    myDatabase = useThisDatabaseInstead; 
  }

  public void doStuff() { 
    ... 
    myDatabase.getData(); 
    ... 
  } 
}
49
JaneGoodall

依存性注入(DI)とは何ですか?

他の人が言ったように、Dependency Injection(DI)は、関心のあるクラス(消費者クラス)が依存する他のオブジェクトインスタンスの直接作成と寿命の管理の責任を取り除きます(- MLセンス )。代わりに、これらのインスタンスは、通常、コンストラクターパラメーターとして、またはプロパティセッターを介して、コンシューマクラスに渡されます(コンシューマクラスへのインスタンス化とパスの依存関係オブジェクトの管理は、通常Inversion of Control(IoC)コンテナですが、それは別のトピックです)。

DI、DIPおよびSOLID

具体的には、Robert C Martinの Object Oriented Designの固体原理 のパラダイムでは、DIDependency Inversion Principle(DIP) の可能な実装の1つです。 DIPはDマントラのSOLIDです -他のDIP実装には、Service LocatorおよびPluginパターンが含まれます。

DIPの目的は、クラス間の緊密で具体的な依存関係を分離することです。代わりに、使用する言語とアプローチに応じて、interfaceabstract class、またはpure virtual classを介して達成できる抽象化によって結合を緩めます。

DIPがない場合、私たちのコード(私はこの「消費クラス」と呼んでいます)は具体的な依存関係に直接結合されており、この依存関係のインスタンスを取得および管理する方法を知る責任、つまり概念的にもしばしば負担になります:

"I need to create/use a Foo and invoke method `GetBar()`"

一方、DIPの適用後、要件は緩和され、Foo依存関係の有効期間を取得および管理する懸念はなくなりました。

"I need to invoke something which offers `GetBar()`"

DIP(およびDI)を使用する理由

この方法でクラス間の依存関係を分離すると、抽象化の前提条件も満たす他の実装とのこれらの依存関係クラスのeasy substitutionが可能になります(たとえば、同じインターフェイスの別の実装で依存関係を切り替えることができます)。さらに、他の人が言及したように、おそらくthe DIPを介してクラスを分離する最も一般的な理由は、これらの同じ依存関係をスタブおよび/またはモックできるため、消費クラスを分離してテストできるようにするためです。

DIの結果の1つは、依存関係オブジェクトが(コンストラクターまたはセッターインジェクションを介して)消費クラスに渡されるため、依存オブジェクトインスタンスの寿命管理が消費クラスによって制御されなくなることです。

これはさまざまな方法で表示できます。

  • 消費クラスによる依存関係の寿命制御を保持する必要がある場合、依存クラスインスタンスを作成するための(抽象)ファクトリをコンシューマクラスに注入することにより、制御を再確立できます。コンシューマーは、必要に応じてファクトリー上のCreateを介してインスタンスを取得し、これらのインスタンスを完了すると破棄できます。
  • または、依存関係インスタンスの寿命制御をIoCコンテナに放棄することができます(これについては以下で詳しく説明します)。

DIを使用する場合?

  • 同等の実装を依存関係に置き換える必要がある場合、
  • クラスのメソッドをその依存関係から切り離して単体テストする必要があるときはいつでも、
  • 依存関係の寿命の不確実性が実験に値する場合(たとえば、MyDepClassはスレッドセーフです-シングルトンにしてすべてのコンシューマに同じインスタンスを注入するとどうなりますか?)

簡単なC#実装を次に示します。以下の消費クラスがある場合:

public class MyLogger
{
   public void LogRecord(string somethingToLog)
   {
      Console.WriteLine("{0:HH:mm:ss} - {1}", DateTime.Now, somethingToLog);
   }
}

一見無害に見えますが、他の2つのクラスSystem.DateTimeSystem.Consoleに2つのstatic依存関係があり、これらはロギング出力オプションを制限するだけでなく(誰も見ていない場合、コンソールへのロギングは価値がありません)、さらに悪いことに、与えられたテストを自動的に行うことは困難です非決定的なシステムクロックへの依存。

ただし、タイムスタンプの依存関係を依存関係として抽象化し、DIPを単純なインターフェイスにのみ結合することにより、このクラスにMyLoggerを適用できます。

public interface IClock
{
    DateTime Now { get; }
}

また、Consoleへの依存関係を、TextWriterなどの抽象化に緩めることもできます。依存性注入は、通常、constructor注入(抽象化を消費クラスのコンストラクターへのパラメーターとして依存性に渡す)またはSetter InjectionsetXyz() setterまたは{set;}を定義した.Netプロパティを介して依存関係を渡す)として実装されます。コンストラクターインジェクションが推奨されます。これにより、構築後にクラスが正しい状態になり、内部依存関係フィールドをreadonly(C#)またはfinal(Java)としてマークできるようになるためです。したがって、上記の例でコンストラクター注入を使用すると、次のようになります。

public class MyLogger : ILogger // Others will depend on our logger.
{
    private readonly TextWriter _output;
    private readonly IClock _clock;

    // Dependencies are injected through the constructor
    public MyLogger(TextWriter stream, IClock clock)
    {
        _output = stream;
        _clock = clock;
    }

    public void LogRecord(string somethingToLog)
    {
        // We can now use our dependencies through the abstraction 
        // and without knowledge of the lifespans of the dependencies
        _output.Write("{0:yyyy-MM-dd HH:mm:ss} - {1}", _clock.Now, somethingToLog);
    }
}

(具体的なClockを提供する必要があります。もちろん、これはDateTime.Nowに戻すことができ、2つの依存関係はコンストラクターインジェクションを介してIoCコンテナーによって提供する必要があります)

自動化された単体テストを構築できます。これにより、ロガーが正しく動作していることを明確に証明できます。依存関係-時間を制御できるようになり、書き込まれた出力を確認できます。

[Test]
public void LoggingMustRecordAllInformationAndStampTheTime()
{
    // Arrange
    var mockClock = new Mock<IClock>();
    mockClock.Setup(c => c.Now).Returns(new DateTime(2015, 4, 11, 12, 31, 45));
    var fakeConsole = new StringWriter();

    // Act
    new MyLogger(fakeConsole, mockClock.Object)
        .LogRecord("Foo");

    // Assert
    Assert.AreEqual("2015-04-11 12:31:45 - Foo", fakeConsole.ToString());
}

次のステップ

依存関係の注入は、常に Inversion of Control container(IoC) に関連付けられ、具体的な依存関係インスタンスを注入(提供)し、寿命インスタンスを管理します。構成/ブートストラップ処理中に、IoCコンテナにより、以下を定義できます。

  • 各抽象化と設定された具象実装との間のマッピング(例"コンシューマがIBarを要求するたびに、ConcreteBarインスタンスを返す"
  • 各依存関係の寿命管理のためにポリシーを設定できます。各コンシューマインスタンスに新しいオブジェクトを作成する、すべてのコンシューマでシングルトン依存関係インスタンスを共有する、同じスレッドでのみ同じ依存関係インスタンスを共有するなど。
  • .Netでは、IoCコンテナーはIDisposableなどのプロトコルを認識しており、構成されたライフスパン管理に従ってDisposing依存関係の責任を引き受けます。

通常、IoCコンテナーの構成/ブートストラップが完了すると、バックグラウンドでシームレスに動作し、コーダーは依存関係を気にすることなく手元のコードに集中できます。

DIフレンドリーなコードの鍵は、クラスの静的な結合を避け、依存関係の作成にnew()を使用しないことです

上記の例のように、依存関係の分離には設計作業が必要であり、開発者にとっては、newing依存関係の習慣を直接破り、代わりに依存関係を管理するためにコンテナを信頼するために必要なパラダイムシフトがあります。

しかし、特に関心のあるクラスを徹底的にテストできるという点で、多くの利点があります。

:POCO/POJO /シリアル化DTO /エンティティグラフ/匿名JSONプロジェクションなどの作成/マッピング/プロジェクション(new ..()経由) -すなわち、「データのみ」のクラスまたはレコード-使用またはメソッドから返されるnotは、依存関係(UMLの意味で)と見なされ、DIの対象ではありません。 newを使用してこれらを投影するのは問題ありません。

36
StuartLC

依存性注入の概念を理解しやすくするため。電球を切り替える(オン/オフ)ためのスイッチボタンの例を見てみましょう。

依存性注入なし

スイッチはどの電球に接続されているかを事前に知っておく必要があります(ハードコードされた依存関係)。そう、

Switch - > PermanentBulb //スイッチは恒久的な電球に直接接続されているため、テストは簡単にできません

Switch(){
PermanentBulb = new Bulb();
PermanentBulb.Toggle();
}

依存性注入あり

スイッチは、電球が私に渡された場合は、オン/オフを切り替える必要があることを知っているだけです。そう、

スイッチ - >電球1 OR電球2 OR NightBulb(依存関係の注入)

Switch(AnyBulb){ //pass it whichever bulb you like
AnyBulb.Toggle();
}

James スイッチと電球の例の変更:

public class SwitchTest { 
  TestToggleBulb() { 
    MockBulb mockbulb = new MockBulb(); 

    // MockBulb is a subclass of Bulb, so we can 
    // "inject" it here: 
    Switch switch = new Switch(mockBulb); 

    switch.ToggleBulb(); 
    mockBulb.AssertToggleWasCalled(); 
  } 
}

public class Switch { 
  private Bulb myBulb; 

  public Switch() { 
    myBulb = new Bulb(); 
  } 

  public Switch(Bulb useThisBulbInstead) { 
    myBulb = useThisBulbInstead; 
  } 

  public void ToggleBulb() { 
    ... 
    myBulb.Toggle(); 
    ... 
  } 
}`
33
wakqasahmed

依存性注入(DI)のポイントは、アプリケーションのソースコードを clean および stable に保つことです。

  • clean 依存関係初期化コードの/
  • 安定 使用されている依存関係にかかわらず

実際には、すべてのデザインパターンが懸念を切り離し、将来の変更が最小限のファイルに影響を与えるようにします。

DIの特定のドメインは、依存関係の設定と初期化の委任です。

例:シェルスクリプト付きのDI

ときどきJavaの外部で作業する場合は、sourcename__が多くのスクリプト言語(シェル、Tclなど、またはこの目的のために誤用されたPythonのimportname__)でよく使用される方法を思い出してください。

単純なdependent.shスクリプトを考えてください。

#!/bin/sh
# Dependent
touch         "one.txt" "two.txt"
archive_files "one.txt" "two.txt"

このスクリプトは依存しています。単独では正常に実行されません(archive_filesは定義されていません)。

archive_files実装スクリプトでarchive_files_Zip.shを定義します(この場合はZipname__を使用します)。

#!/bin/sh
# Dependency
function archive_files {
    Zip files.Zip "[email protected]"
}

sourcename実装スクリプトを直接依存スクリプトに含める代わりに、両方の「コンポーネント」をラップするinjector.sh「コンテナ」を使用します。

#!/bin/sh 
# Injector
source ./archive_files_Zip.sh
source ./dependent.sh

archive_files dependency 注入 dependent スクリプトに追加したところです。

tarname__またはxzname__を使ってarchive_filesを実装する依存性を注入したかもしれません。

例:DIを削除する

dependent.shスクリプトが依存関係を直接使用していた場合、そのアプローチは 依存関係検索 となります(これは 依存関係注入 とは反対です)。

#!/bin/sh
# Dependent

# dependency look-up
source ./archive_files_Zip.sh

touch         "one.txt" "two.txt"
archive_files "one.txt" "two.txt"

今問題は、依存する「コンポーネント」が初期化自体を実行しなければならないということです。

"component"のソースコードは clean でも stable でもありません。依存関係の初期化を変更するたびに "components"のソースコードファイルの新しいリリースが必要になるためです。

最後の言葉

DIは、Javaフレームワークほど広くは強調されず普及していません。

しかし、それは懸念を分ける一般的なアプローチです。

  • アプリケーション 開発 シングル ソースコードリリースライフサイクル)
  • application deployment multiple 独立したライフサイクルを持つターゲット環境)

dependency lookup のみで設定を使用することは、依存ごとにサポートされる依存の種類の数(新しいデータベースの種類など)と同様に、依存関係ごとに設定パラメータの数が変わる可能性があるため役に立ちません。

25
uvsmtid

上記の答えはすべて良いです、私の目的は、プログラミングの知識がない人でも概念を理解できるように、簡単な方法で概念を説明することです

依存性注入は、複雑なシステムをより簡単に作成するのに役立つ設計パターンの1つです。

私たちは日々の生活の中でこのパターンの多種多様なアプリケーションを見ることができます。いくつかの例は、テープレコーダー、VCD、CDドライブなどです。

Reel-to-reel portable tape recorder, mid-20th century.

上記の画像は、20世紀半ばのリールツーリールポータブルテープレコーダーの画像です。 ソース

テープレコーダーマシンの主な目的は、サウンドを録音または再生することです。

システムの設計中に、サウンドまたは音楽を録音または再生するにはリールが必要です。このシステムを設計するには2つの可能性があります

  1. マシン内にリールを配置できます
  2. リールを配置できるフックを提供できます。

最初のものを使用する場合は、マシンを開いてリールを変更する必要があります。 2番目のリール、つまりリール用のフックを選択した場合、リールを変更することで音楽を再生できるという追加の利点が得られます。また、リール内の何でも演奏することだけに機能を減らします。

賢明な依存関係注入と同様に、依存関係を外部化してコンポーネントの特定の機能のみに焦点を当て、独立したコンポーネントを結合して複雑なシステムを形成できるようにするプロセスです。

依存性注入を使用して達成した主な利点。

  • 高い凝集力と疎結合。
  • 依存関係を外部化し、責任のみに注目する。
  • 物をコンポーネントとして作成し、組み合わせて高機能の大規模システムを形成します。
  • 独自に開発され、適切にテストされているため、高品質のコンポーネントを開発するのに役立ちます。
  • コンポーネントに障害が発生した場合、コンポーネントを別のものに置き換えると役立ちます。

現在、これらの概念は、プログラミングの世界でよく知られているフレームワークの基礎を形成しています。 Spring Angularなどは、この概念の上に構築された有名なソフトウェアフレームワークです。

依存性注入は、コンパイル時に他のオブジェクトが依存するオブジェクトのインスタンスを作成するために使用されるパターンです。どのクラスを使用してその機能を提供するか、またはオブジェクトにプロパティを注入する方法を依存性注入と呼びます。

依存性注入の例

以前は、このようなコードを書いていました

Public MyClass{
 DependentClass dependentObject
 /*
  At somewhere in our code we need to instantiate 
  the object with new operator  inorder to use it or perform some method.
  */ 
  dependentObject= new DependentClass();
  dependentObject.someMethod();
}

依存性注入では、依存性インジェクターがインスタンス化を解除します

Public MyClass{
 /* Dependency injector will instantiate object*/
 DependentClass dependentObject

 /*
  At somewhere in our code we perform some method. 
  The process of  instantiation will be handled by the dependency injector
 */ 

  dependentObject.someMethod();
}

また読むことができます

制御の反転と依存性注入の違い

19
Samuel J Mathew

依存性注入とは何ですか?

依存性注入(DI)は、互いに依存しているオブジェクトを分離することを意味します。オブジェクトAがオブジェクトBに依存しているとすると、アイデアはこれらのオブジェクトを互いに切り離すことです。コンパイル時にもかかわらず、実行時にオブジェクトへの依存関係を共有するのではなく、新しいキーワードを使用してオブジェクトをハードコーディングする必要はありません。 

依存性注入がSpringでどのように機能するか

コンフィグレーションファイルでBeanの依存関係を定義するのではなく、newキーワードを使用してオブジェクトをハードコードする必要はありません。春コンテナはすべてをフックする責任があります。

制御の反転(IOC)

IOCは一般的な概念であり、さまざまな方法で表現することができ、依存性注入はIOCの1つの具体例です。

2種類の依存性注入

  1. コンストラクタインジェクション
  2. セッター注入

1.コンストラクタベースの依存性注入

コンストラクタベースのDIは、コンテナが、それぞれ他のクラスへの依存関係を表す多数の引数を使用してクラスコンストラクタを呼び出すときに実行されます。

public class Triangle {

private String type;

public String getType(){
    return type;
 }

public Triangle(String type){   //constructor injection
    this.type=type;
 }
}
<bean id=triangle" class ="com.test.dependencyInjection.Triangle">
        <constructor-arg value="20"/>
  </bean>

2.セッターベースの依存性注入

セッターベースのDIは、引数のないコンストラクターまたは引数のない静的ファクトリーメソッドを呼び出してBeanをインスタンス化した後に、コンテナーがBeanのセッターメソッドを呼び出すことによって実現されます。

public class Triangle{

 private String type;

 public String getType(){
    return type;
  }
 public void setType(String type){          //setter injection
    this.type = type;
  }
 }

<!-- setter injection -->
 <bean id="triangle" class="com.test.dependencyInjection.Triangle">
        <property name="type" value="equivialteral"/>

注:必須の依存関係にはコンストラクター引数を使用し、オプションの依存関係にはセッターを使用することをお勧めします。 setterに@Requiredアノテーションよりもアノテーションベースを使用する場合は、必要な依存関係としてsetterを作成するために使用できます。

17
Harleen

私が考えることができる最もよく似たものは外科医と手術室の彼の助手であり、そこでは外科医が主な人物であり、そして外科医が必要なときに様々な外科用部品を提供する彼が一番やること(手術)。アシスタントがなければ、外科医は自分が必要とするたびに自分で部品を手に入れなければなりません。

略してDIは、依存コンポーネントをそれに提供することによってそれをフェッチするためのコンポーネントに対する共通の追加の責任(負担)を取り除くための技法です。

DIは、surgeon who can concentrate on surgeryのように、単一責任(SR)の原則に近づきます。

DIを使用する場合:ほとんどすべてのプロダクションプロジェクト(小規模/大規模)、特に絶え間なく変化するビジネス環境でDIを使用することをお勧めします。

理由:変更をすばやくテストして市場に投入できるように、コードを簡単にテスト可能、モック可能などにしたいのです。あなたがより多くのコントロールを持っているコードベースへの旅行であなたをサポートするための素晴らしい無料のツール/フレームワークがたくさんあるのに、なぜあなたはそうしないのですか。

15
Anwar Husain

つまり、オブジェクトは、その役割を果たすのに必要なだけの依存関係を持ち、依存関係は少なくなるはずです。さらに、可能であれば、オブジェクトの依存関係は「具象」オブジェクトではなく、インタフェースに依存する必要があります。疎結合は、再利用性を高め、保守性を高め、高価なサービスの代わりに「モック」オブジェクトを簡単に提供できるようにします。

「依存性注入」(DI)は「制御の反転」(IoC)とも呼ばれ、この疎結合を促進するための手法として使用できます。

DIを実装するには、主に2つの方法があります。

  1. コンストラクタインジェクション 
  2. セッター注入

コンストラクタインジェクション

これは、オブジェクトの依存関係をコンストラクタに渡す手法です。

コンストラクタは、具象オブジェクトではなくインタフェースを受け入れます。また、orderDaoパラメータがnullの場合は例外がスローされます。これは、有効な依存関係を受け取ることの重要性を強調しています。私の考えでは、コンストラクタインジェクションはオブジェクトにその依存関係を与えるための好ましいメカニズムです。適切な実行のためにどの依存性が“ Person”オブジェクトに与えられる必要があるかは、オブジェクトを呼び出す間、開発者にとって明らかである。

セッター注入

しかし、次の例を考えてみましょう。依存関係のない10個のメソッドを持つクラスがあり、IDAOに依存する新しいメソッドを追加しているとします。あなたはConstructor Injectionを使うようにコンストラクタを変更することができます、しかしこれはあなたに至る所ですべてのコンストラクタ呼び出しへの変更を強制するかもしれません。あるいは、依存関係を取る新しいコンストラクターを追加するだけで、開発者は、あるコンストラクターを他のコンストラクターに対してどのように使用するかを簡単に知ることができます。最後に、依存関係を作成するのに非常にコストがかかる場合、それがめったに使用されない場合になぜそれを作成してコンストラクタに渡す必要があるのでしょうか。 「セッター注入」は、このような状況で使用できるもう1つのDI技法です。

Setter Injectionは、依存関係がコンストラクタに渡されることを強制しません。代わりに、依存関係は、必要としているオブジェクトによって公開されるパブリックプロパティに設定されます。前述のように、これを行う主な動機は次のとおりです。

  1. レガシークラスのコンストラクタを変更することなく依存性注入をサポートします。
  2. 高価なリソースやサービスをできるだけ遅く、必要なときにだけ作成できるようにする。

これは上記のコードがどのように見えるかの例です。

public class Person {
    public Person() {}

    public IDAO Address {
        set { addressdao = value; }
        get {
            if (addressdao == null)
              throw new MemberAccessException("addressdao" +
                             " has not been initialized");
            return addressdao;
        }
    }

    public Address GetAddress() {
       // ... code that uses the addressdao object
       // to fetch address details from the datasource ...
    }

    // Should not be called directly;
    // use the public property instead
    private IDAO addressdao;
13

例として、2つのクラスClientServiceがあります。 ClientServiceを使用します

public class Service {
    public void doSomeThingInService() {
        // ...
    }
}

依存性注入なし

方法1)  

public class Client {
    public void doSomeThingInClient() {
        Service service = new Service();
        service.doSomeThingInService();
    }
}

方法2)

public class Client {
    Service service = new Service();
    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

方法3)  

public class Client {
    Service service;
    public Client() {
        service = new Service();
    }
    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

1)2)3) を使う

Client client = new Client();
client.doSomeThingInService();

利点

  • 単純な

デメリット

  • テスト用の難しいClientクラス
  • Serviceコンストラクタを変更するとき、すべての場所でコードを変更する必要がありますcreate Service object

依存性注入を使用する

方法1) コンストラクタ注入

public class Client {
    Service service;

    Client(Service service) {
        this.service = service;
    }

    // Example Client has 2 dependency 
    // Client(Service service, IDatabas database) {
    //    this.service = service;
    //    this.database = database;
    // }

    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

使用中 

Client client = new Client(new Service());
// Client client = new Client(new Service(), new SqliteDatabase());
client.doSomeThingInClient();

方法2) セッター注入

public class Client {
    Service service;

    public void setService(Service service) {
        this.service = service;
    }

    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

使用中 

Client client = new Client();
client.setService(new Service());
client.doSomeThingInClient();

方法3) インターフェース注入

チェック https://en.wikipedia.org/wiki/Dependency_injection

=== 

さて、このコードはすでにDependency Injectionに従っており、テストClientクラスのほうが簡単です。
しかし、私たちはまだnew Service()を何度も使っていて、Serviceコンストラクタを変更するのは良くありません。それを防ぐために、DIインジェクタを使うことができます
1)簡単なマニュアルInjector

public class Injector {
    public static Service provideService(){
        return new Service();
    }

    public static IDatabase provideDatatBase(){
        return new SqliteDatabase();
    }
    public static ObjectA provideObjectA(){
        return new ObjectA(provideService(...));
    }
}

を使用

Service service = Injector.provideService();

2)使用ライブラリ:Android用 dagger2

利点

  • テストを簡単にする
  • あなたがServiceを変えるとき、あなたはそれをInjectorクラスで変える必要があるだけです
  • Use Constructor Injectionを使った場合、Clientのコンストラクタを見ると、Clientクラスの依存関係がいくつあるかがわかります。

デメリット  

  • Use Constructor Injectionを使用する場合、ServiceオブジェクトはClientが作成されたときに作成されます。ときにはClientを使用せずにServiceクラスで関数を使用するので、作成されたServiceは無駄になります。

依存性注入の定義

https://en.wikipedia.org/wiki/Dependency_injection

依存関係は使用できるオブジェクトです(Service
注入とは、依存関係(Service)をそれを使用する依存オブジェクト(Client)に渡すことです。

12
Linh

みんながDIのために書いたので、私はいくつかの質問をさせてください..

  1. あなたがDIの設定をしているとき、すべての実際の実装(インターフェースではない)がクラスに注入されることになっている(例えば、コントローラーへのサービスのために)なぜそれはある種のハードコーディングではないのですか? 
  2. 実行時にオブジェクトを変更したい場合はどうすればいいですか?たとえば、MyControllerをインスタンス化したときに、私の設定は既にILLoggerとしてFileLoggerをインジェクトすると言っています。しかし、私はDatabaseLoggerを注入したいかもしれません。 
  3. 私のAClassが必要とするオブジェクトを変更したいときはいつも、2つの場所 - クラス自身と設定ファイル - を調べる必要があります。それはどうして人生を楽にするのでしょうか。
  4. AClassのApropertyが注入されていない場合、それを模擬するのは難しいですか? 
  5. 最初の質問に戻ります。 new object()を使用するのが悪い場合、インタフェースではなく実装をインジェクトするのはどうしてでしょうか。私たちが実際にインターフェースをインジェクトしていると言っている人も多いと思いますが、設定によってそのインターフェースの実装を指定することができます。実行時にはハードコーディングされません。

これは、@ Adam Nが投稿した回答に基づいています。

なぜPersonServiceはGroupMembershipServiceについて心配する必要がなくなったのですか? GroupMembershipには、それが依存する複数のもの(オブジェクト/プロパティ)があることを説明しました。 PServiceにGMServiceが必要な場合は、それをプロパティとして使用します。あなたがそれを注射したかどうかにかかわらず、あなたはそれを模擬することができます。私がそれを注入したいのは、GMServiceがより具体的な子クラスを持っている場合だけです。これは実行時までわからないでしょう。それならサブクラスを注入したいのです。または、シングルトンまたはプロトタイプとしてそれを使用したい場合は。正直に言うと、設定ファイルには、コンパイル時にどのサブクラスの型(インタフェース)を挿入するかについて、ハードコーディングされたものがすべて含まれています。 

_編集_  

DIにJose Maria Arranzがいいコメント

DIは依存関係の方向性を判断し、グルーコードを書く必要性を排除することによって結束力を高めます。

偽です。依存関係の方向はXML形式であるかアノテーションとしてあります。あなたの依存関係はXMLコードとアノテーションとして書かれています。 XMLと注釈はソースコードです。

DIは、すべてのコンポーネントをモジュール式(交換可能)にすることでカップリングを減らし、互いに明確に定義されたインターフェースを持ちます。

偽です。あなたは、インターフェイスに基づいてモジュラーコードを構築するためにDIフレームワークを必要としません。

置き換え可能について:非常に単純な.propertiesアーカイブとClass.forNameを使って、クラスを変更できるように定義することができます。あなたのコードのクラスを変更することができるのであれば、Javaはあなたのためではありません。スクリプト言語を使用してください。ところで、注釈は再コンパイルしないと変更できません。

私の意見では、DIの枠組みにはボイラープレートの削減という唯一の理由があります。優れたファクトリシステムを使用すると、好みのDIフレームワークと同じ、より制御された、予測可能なものを実行できます。DIフレームワークはコード削減を約束します(XMLと注釈もソースコードです)。問題は、このボイラープレートの削減が非常に単純な場合(クラスごとに1つのインスタンスなど)では実際には発生することです。

10
Chookoos

依存性注入 は、コードの一部(クラスなど)が依存関係(コードの他の部分、他のクラスなどに依存する)にアクセスするための方法(実際には any-way )を意味します。ハードコードされていなくてもモジュール方式で(必要に応じて自由に変更したり上書きしたり、別の時点で読み込むこともできます)

(そしてps、そう、それはかなり単純な概念のために過度に宣伝された25 $の名前になった)、私の.25セント

8
Nikos M.

私はすでに多くの答えがあることを知っています、しかし私はこれが非常に役に立ちました: http://tutorials.jenkov.com/dependency-injection/index.html

依存関係なし

public class MyDao {

  protected DataSource dataSource =
    new DataSourceImpl("driver", "url", "user", "password");

  //data access methods...
  public Person readPerson(int primaryKey) {...}

}

依存:

public class MyDao {

  protected DataSource dataSource = null;

  public MyDao(String driver, String url, String user, String
 password){
    this.dataSource = new DataSourceImpl(driver, url, user, password);
  }

  //data access methods...
  public Person readPerson(int primaryKey)
  {...}

}

DataSourceImplのインスタンス化がどのようにコンストラクターに移動されたかに注目してください。コンストラクタはDataSourceImplが必要とする4つの値である4つのパラメータを取ります。 MyDaoクラスは依然としてこれら4つの値に依存していますが、もはやこれらの依存関係自体を満たすことはできません。それらはMyDaoインスタンスを作成するどんなクラスによっても提供されます。

7
Ali Issa

人気のある答えは役に立たない、なぜならそれらは有用ではない方法で依存性注入を定義するからである。 「依存性」とは、オブジェクトXが必要とする既存の他のオブジェクトを意味することに同意しましょう。しかし、私たちが言うときに「依存性注入」をしているとは言いません。

$foo = Foo->new($bar);

コンストラクタに渡すパラメータを呼び出すだけです。コンストラクタが発明されて以来、私たちはこれを定期的に行ってきました。

「依存性注入」は一種の「制御の逆転」と見なされます。つまり、呼び出し側から何らかのロジックが取り出されるということです。呼び出し側がパラメータを渡す場合はそうではありません。したがって、それがDIの場合、DIは制御の逆転を意味するものではありません。

DIは、呼び出し元と依存関係を管理するコンストラクターの間に中間レベルがあることを意味します。 Makefileは依存性注入の簡単な例です。 「呼び出し元」はコマンドラインで「make bar」と入力する人であり、「コンストラクタ」はコンパイラです。 Makefileはbarがfooに依存することを指定し、そして

gcc -c foo.cpp; gcc -c bar.cpp

する前に

gcc foo.o bar.o -o bar

"make bar"とタイプした人は、barがfooに依存していることを知る必要はありません。依存関係は "make bar"とgccの間に挿入されました。

中間レベルの主な目的は、依存関係をコンストラクターに渡すだけでなく、すべての依存関係を 1か所 - にリストし、それらをコーダーから隠すことです(コーダーにそれらを提供させないため) 。

通常、中間レベルは構築されたオブジェクトのファクトリを提供します。これは、要求された各オブジェクトタイプが満たす必要がある役割を提供する必要があります。それは、建設の詳細を隠す中間レベルを持つことによって、すでに工場によって課された抽象化のペナルティを被っているので、工場を使うこともできるからです。

7
Phil Goetz

依存性注入は、一般に「依存性難読化」要件と呼ばれるものに対する考えられる解決策の1つです。依存関係の難読化は、それを必要とするクラスに依存関係を提供するプロセスから「明白な」性質を取り去り、そのため、何らかの方法で、そのクラスへの依存関係の提供を難読化する方法です。これは必ずしも悪いことではありません。実際、依存関係をクラスに提供する方法を難読化することにより、クラス外の何かが依存関係を作成する責任があります。これは、さまざまなシナリオで、変更を加えずに依存関係の異なる実装をクラスに提供できることを意味しますクラスに。これは、プロダクションモードとテストモードを切り替えるのに最適です(たとえば、「モック」サービスの依存関係を使用する)。

残念なことに、一部の人々は、依存関係の難読化を行うために特別なフレームワークが必要であると想定していることと、特定のフレームワークを使用しないことを選択した場合、何らかの方法で「より少ない」プログラマーであるということです。多くの人が信じている非常に邪魔なもう一つの神話は、依存性注入が依存性難読化を達成する唯一の方法であるというものです。これは明らかに歴史的にも明らかに100%間違っていますが、依存関係の難読化要件に依存関係の注入に代わるものがあることを一部の人々に納得させるのは困難です。

プログラマーは何年もの間依存関係の難読化の要件を理解しており、多くの代替ソリューションが依存関係の注入が考えられる前後に進化してきました。 Factoryパターンはありますが、特定のインスタンスへの注入が不要なThreadLocalを使用する多くのオプションもあります-依存関係は、オブジェクトを(便利な静的getterメソッドを介して)利用可能にする利点があるスレッドに効果的に注入されますanyそれを必要とするクラスは、それを必要とするクラスに注釈を追加する必要なく、それを実現するために複雑なXML「接着剤」をセットアップする必要はありません。永続性(JPA/JDOなど)に依存関係が必要な場合、POJOだけで構成されるドメインモデルとビジネスモデルクラス(つまり、フレームワーク固有/アノテーションでロックされていない)を使用して、「透過的永続性」をはるかに簡単に実現できます。

6
Volksman

『The Book from the /』、「 十分に根拠のあるJava Developer:Java 7の重要なテクニック、そしてポリグロット・プログラミング

DIはIoCの特定の形式であり、依存関係を見つけるプロセスは、現在実行中のコードを直接制御することはできません。

5
TastyCode

依存性注入(DI)は、デザインパターンの1つで、OOPの基本機能、つまりあるオブジェクトと別のオブジェクトとの関係を使用します。継承は1つのオブジェクトを継承して、より複雑で具体的な別のオブジェクトを実行しますが、関係または関連付けは、attributeを使用して1つのオブジェクトから別のオブジェクトへのポインタを作成するだけです。 DIの力は、インタフェースや隠しコードのように、他のOOPの機能と組み合わされています。単純さ.

本のインターフェース:

package com.deepam.hidden;

public interface BookInterface {

public BookInterface setHeight(int height);
public BookInterface setPages(int pages);   
public int getHeight();
public int getPages();  

public String toString();
}

次に私たちは多くの種類の本を持つことができます。タイプの一つはフィクションです:

package com.deepam.hidden;

public class FictionBook implements BookInterface {
int height = 0; // height in cm
int pages = 0; // number of pages

/** constructor */
public FictionBook() {
    // TODO Auto-generated constructor stub
}

@Override
public FictionBook setHeight(int height) {
  this.height = height;
  return this;
}

@Override
public FictionBook setPages(int pages) {
  this.pages = pages;
  return this;      
}

@Override
public int getHeight() {
    // TODO Auto-generated method stub
    return height;
}

@Override
public int getPages() {
    // TODO Auto-generated method stub
    return pages;
}

@Override
public String toString(){
    return ("height: " + height + ", " + "pages: " + pages);
}
}

今購読者は本への関連付けを持つことができます:

package com.deepam.hidden;

import Java.lang.reflect.Constructor;
import Java.lang.reflect.InvocationTargetException;

public class Subscriber {
BookInterface book;

/** constructor*/
public Subscriber() {
    // TODO Auto-generated constructor stub
}

// injection I
public void setBook(BookInterface book) {
    this.book = book;
}

// injection II
public BookInterface setBook(String bookName) {
    try {
        Class<?> cl = Class.forName(bookName);
        Constructor<?> constructor = cl.getConstructor(); // use it for parameters in constructor
        BookInterface book = (BookInterface) constructor.newInstance();
        //book = (BookInterface) Class.forName(bookName).newInstance();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
    return book;
}

public BookInterface getBook() {
  return book;
}

public static void main(String[] args) {

}

}

3つのクラスはすべてそれ自身の実装のために隠すことができます。これでDIにこのコードを使うことができます。

package com.deepam.implement;

import com.deepam.hidden.Subscriber;
import com.deepam.hidden.FictionBook;

public class CallHiddenImplBook {

public CallHiddenImplBook() {
    // TODO Auto-generated constructor stub
}

public void doIt() {
    Subscriber ab = new Subscriber();

    // injection I
    FictionBook bookI = new FictionBook();
    bookI.setHeight(30); // cm
    bookI.setPages(250);
    ab.setBook(bookI); // inject
    System.out.println("injection I " + ab.getBook().toString());

    // injection II
    FictionBook bookII = ((FictionBook) ab.setBook("com.deepam.hidden.FictionBook")).setHeight(5).setPages(108); // inject and set
    System.out.println("injection II " + ab.getBook().toString());      
}

public static void main(String[] args) {
    CallHiddenImplBook kh = new CallHiddenImplBook();
    kh.doIt();
}
}

依存性注入を使用する方法はたくさんあります。シングルトンなどと組み合わせることは可能ですが、それでも基本的には他のオブジェクトの中にオブジェクト型の属性を作成することによって実現される関連付けにすぎません。何度も何度も書く必要があります私たちのために常に準備され、行われています。これが、DIが制御の反転(IoC)と非常に密接に結び付いているためです。つまり、プログラムが実行中の別のモジュールに制御を渡し、コードがBeanに注入されます。 (注入可能な各オブジェクトは署名されるか、またはBeanと見なされる可能性があります。)たとえばSpringでは、これは ApplicationContext containerの作成および初期化によって行われます。コード内でコンテキストを作成し、Beanの初期化を呼び出すだけです。その瞬間に注入は自動的に行われました。

4
hariprasad

book /から - Apress.Spring.Persistence.with.Hibernate.Oct.2010

依存性注入の目的は、外部ソフトウェアコンポーネントをアプリケーションビジネスロジックから解決する作業を分離することです。コンポーネントのコードに戸惑います。これは、エラーの可能性を高め、コードを膨らませ、そして保守の複雑さを増大させるだけではありません。それはコンポーネントをより密接に結合し、リファクタリングやテストの際に依存関係を修正することを困難にします。

簡単に言うと、依存性注入(DI)は、依存性を除去したり、異なるオブジェクト間の密接な結合を排除したりする方法です。依存性注入は、各オブジェクトにまとまりのある動作を与えます。 

DIはSpringのIOCプリンシパルの実装です。依存性注入プログラマを使用すると、newキーワードを使用してオブジェクトを作成する必要がありません。 

オブジェクトは一度Springコンテナにロードされ、getBean(String beanName)メソッドを使ってSpringコンテナからそれらのオブジェクトを取得することで、必要に応じていつでも再利用します。

3
Waqas Ahmed

依存性注入(DI)は、依存性反転原理(DIP)プラクティスの一部であり、制御の反転(IoC)とも呼ばれます。基本的にDIPを実行する必要があるのは、1つのモノリシックシステムではなく、コードをよりモジュール化し、単体テスト可能にしたいからです。そこで、クラスから切り離して抽象化することができるコードの部分を識別し始めます。抽象化の実装はクラスの外部からインジェクトする必要があります。通常、これはコンストラクタを介して実行できます。そのため、抽象化をパラメータとして受け入れるコンストラクタを作成します。これを(コンストラクタによる)依存性注入と呼びます。 DIP、DI、およびIoCコンテナの詳細については、 こちら を参照してください。

3

依存性注入は、Spring Frameworkに関連する概念の中心です。任意のプロジェクトの春のフレームワークを作成するときに、極めて重要な役割を果たすことがあります。ここでは、依存性注入が重要になります。

実際に、JavaでクラスAとクラスBの2つのクラスを作成し、クラスBで使用可能な関数が何であれ、クラスAで使用するとします。そのときは依存性注入を使用できます。あるクラスのオブジェクトを別のクラスのオブジェクトにクレートすることができます。同様に、クラス全体を別のクラスにインジェクトしてアクセスできるようにすることもできます。この方法で依存性を克服することができます。

依存性の注入IS 2つのクラスを単純にグルーピングし、ATそれらを分離したままにします。

3
mohit sarsar

技術的な手段ではなく、主な目的に焦点を当て、Dependency Injectionが何であるかについて、少し異なる正確で短い定義を提案します( here から続く)。

依存性注入は、サービスオブジェクトの静的なステートレスグラフを作成するプロセスです。各サービスは、その依存関係によってパラメータ化されます。

アプリケーションで作成するオブジェクトは(Java、C#、その他のオブジェクト指向言語のどちらを使用する場合でも)、通常、2つのカテゴリのいずれかに分類されます。ステートレス、静的、グローバルの「サービスオブジェクト」(モジュール)、およびステートフル、動的、ローカル「データオブジェクト」.

モジュールグラフ(サービスオブジェクトのグラフ)は通常、アプリケーションの起動時に作成されます。これは、Springなどのコンテナを使用して実行できますが、オブジェクトコンストラクタにパラメータを渡すことによって手動で実行することもできます。どちらの方法にも長所と短所がありますが、アプリケーションでDIを使用するためにフレームワークを使用する必要はありません。

1つの要件は、サービスがそれらの依存関係によってパラメータ化されなければならないということです。これが何を意味するのかは、特定のシステムで採用されている言語とアプローチによって異なります。通常、これはコンストラクタパラメータの形式を取りますが、セッターを使用することもオプションです。これはまた、サービスの依存関係がサービスのユーザーから隠されていることを意味します(サービスメソッドを呼び出すとき)。

いつ使うの?モジュール間の依存関係グラフを使用してロジックを別々のモジュールにカプセル化するのに十分なほどアプリケーションのサイズが大きい場合はいつでも、コードの読みやすさと探索性が向上します。

2
adamw

依存性注入は、いくつかの依存関係から切り離されたコンポーネントに依存しないようにする方法であり、これは SOLID ガイドラインに従う

依存性反転の原則:「結石ではなく、抽象化に依存する必要があります。

依存性注入のより良い実装は、コンポーネントを依存性注入コンテナから切り離すことができるため、コンポジションルートデザインパターンです。

コンポジションルートに関するこの素晴らしい記事を推奨します http://blog.ploeh.dk/2011/07/28/CompositionRoot/ Mark Seemann著

この記事の重要なポイントは次のとおりです。

コンポジションルートは、モジュールが一緒に構成されているアプリケーション内の(できれば)一意の場所です。

...

アプリケーションのみがコンポジションルートを持つ必要があります。ライブラリとフレームワークはすべきではありません。

...

DIコンテナは、コンポジションルートからのみ参照される必要があります。他のすべてのモジュールには、コンテナへの参照を含めないでください。

依存性注入フレームワークであるDi-Ninjaのドキュメントは、コンポジションルートと依存性注入の原理がどのように機能するかを示す非常に良い例です。 https://github.com/di-ninja/di-ninja 私が知っているように、コンポジションルートデザインパターンを実装するjavascriptの唯一のDiCです。

1
Jo Takion

Christoffer Noringから、Pablo Deelemanの本“ Learning Angular - Second Edition ":

「私たちのアプリケーションが成長し発展するにつれて、私たちの各コードエンティティは内部的に他のオブジェクトのインスタンスを必要とします。これはソフトウェアエンジニアリングの世界では依存関係としてよく知られています。インジェクタは、必要な依存関係をインスタンス化してブートストラップする責任があるため、クライアントに正常にインジェクトされた瞬間から使用できるようになります。クライアントはそれ自身の依存関係をどのようにインスタンス化するかについては何も知りませんし、それらを使用するために彼らが実装するインタフェースを知っているだけです。」

1
H S Progr

依存性注入 は " 制御の反転 "原則の実装の一種であり、これに基づいてフレームワークが構築されます。

フレームワーク GoFの "Design Pattern"に述べられているように、開発者にそれをさせるメイン制御フローロジックを実装するクラスです。このようにして、フレームワークは制御原理の逆転を実現します。

クラス階層としてではなく、テクニックとして実装する方法です。このIoCの原則は、単に依存性注入です。

_ di _ は主に、クラスインスタンスのマッピングとそのインスタンスへの型参照を外部の「エンティティ」に委譲することで構成されます。オブジェクト、静的クラス、コンポーネント、フレームワークなど。 

クラスインスタンスは " dependencies "であり、参照による呼び出し元コンポーネントとクラスインスタンスの外部バインディングは " injection "です。

OOPの観点から、このテクニックをいろいろな方法で実装することができます。例えば、 コンストラクタ注入 セッター注入 インターフェース注入を参照してください。

参照をオブジェクトに一致させるタスクを実行するように第三者に委任することは、サービスを必要とするコンポーネントを同じサービスの実装から完全に分離したい場合に非常に役立ちます。 

このように、コンポーネントを設計するときは、使用するオブジェクトやサービスの実装の変更を気にせずに、他のオブジェクトと連携するためのインタフェースを信頼しながら、アーキテクチャと特定のロジックに専念できます。完全に置き換えられます(明らかにインターフェースを尊重します)。

1
Ciro Corvino

重要なアプリケーションは、ビジネスロジックを実行するために互いに連携する2つ以上のクラスで構成されています。伝統的に、各オブジェクトは、それが協働するオブジェクト(その依存関係)への独自の参照を取得する責任があります。 DIを適用すると、オブジェクトは作成時にシステム内の各オブジェクトを調整する外部エンティティによって依存関係が与えられます。 つまり、依存関係はオブジェクトに注入されます。

詳しくは こちらにリンクの説明を入力してください

0
Hisham Javed

DIは、あるオブジェクトが別のオブジェクトの存在に責任を負うことなく、実際のオブジェクトが実際に相互作用する方法です。オブジェクトは同等に扱われるべきです。それらはすべて物です。誰もクリエイターのように振る舞うべきではありません。これが、あなたが自分の物に正義を決める方法です。

簡単な例 : 

あなたが医者を必要とするならば、あなたは単に行って、(存在する)医者を見つけます。あなたはあなたを助けるために最初から医者をつくることを考えていないでしょう。彼はすでに存在していて、あなたや他の物に仕えるかもしれません。彼はあなた(一つの物)が彼を必要としているかどうかに関わらず存在する権利を有します。彼の存在は全能の神であり、自然な選択ではないと決心した人。したがって、DIの利点の1つは、宇宙の存続期間中に目的のない生きている不要な冗長オブジェクトを作成しないようにすることです(つまりアプリケーション)。

0
Shadi Namrouti