What is dependency injection?

There have been several questions already posted with specific questions about dependency injection, such as when to use it and what frameworks are there for it. However,

What is dependency injection and when/why should or shouldn't it be used?


Basically, instead of having your objects creating a dependency or asking a factory object to make one for them, you pass the needed dependencies in to the object externally, and you make it somebody else's problem. This "someone" is either an object further up the dependency graph, or a dependency injector (framework) that builds the dependency graph. A dependency as I'm using it here is any other object the current object needs to hold a reference to.

One of the major advantages of dependency injection is that it can make testing lots easier. Suppose you have an object which in its constructor does something like:

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

This can be troublesome when all you want to do is run some unit tests on SomeClass, especially if myObject is something that does complex disk or network access. So now you're looking at mocking myObject but also somehow intercepting the factory call. Hard. Instead, pass the object in as an argument to the constructor. Now you've moved the problem elsewhere, but testing can become lots easier. Just make a dummy myObject and pass that in. The constructor would now look a bit like:

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

This is one style of dependency injection - via the constructor. Several mechanisms are possible.

  • As noted in the comments, one common alternative is to define a do-nothing constructor, and have the dependencies injected via property setters (h/t @MikeVella).
  • Martin Fowler documents a third alternative (h/t @MarcDix), where classes explicitly implement an interface for the dependencies they wish injected.
  • When not using dependency injection (such as in classes that do too much work in their constructors etc.), it tends to become much harder to isolate components in unit testing.

    Back in 2013 when I wrote this answer, this was a major theme on the Google Testing Blog. This remains the biggest advantage to me, as you may not always need the extra flexibility in your run-time design (for instance, for service locator or similar patterns), but you do often need to be able to isolate your classes during testing.


    The best definition I've found so far is one by James Shore:

    "Dependency Injection" is a 25-dollar term for a 5-cent concept. [...] Dependency injection means giving an object its instance variables. [...].

    There is an article by Martin Fowler that may prove useful, too.

    Dependency injection is basically providing the objects that an object needs (its dependencies) instead of having it construct them itself. It's a very useful technique for testing, since it allows dependencies to be mocked or stubbed out.

    Dependencies can be injected into objects by many means (such as constructor injection or setter injection). One can even use specialized dependency injection frameworks (eg Spring) to do that, but they certainly aren't required. You don't need those frameworks to have dependency injection. Instantiating and passing objects (dependencies) explicitly is just as good an injection as injection by framework.


    I found this funny example in terms of loose coupling:

    Any application is composed of many objects that collaborate with each other to perform some useful stuff. Traditionally each object is responsible for obtaining its own references to the dependent objects (dependencies) it collaborate with. This leads to highly coupled classes and hard-to-test code.

    For example, consider a Car object.

    A Car depends on wheels, engine, fuel, battery, etc. to run. Traditionally we define the brand of such dependent objects along with the definition of the Car object.

    Without Dependency Injection (DI):

    class Car{
      private Wheel wh= new NepaliRubberWheel();
      private Battery bt= new ExcideBattery();
    
      //The rest
    }
    

    Here, the Car object is responsible for creating the dependent objects.

    What if we want to change the type of its dependent object - say Wheel - after the initial NepaliRubberWheel() punctures? We need to recreate the Car object with its new dependency say ChineseRubberWheel() , but only the Car manufacturer can do that.

    Then what does the Dependency Injection do us for...?

    When using dependency injection, objects are given their dependencies at run time rather than compile time (car manufacturing time). So that we can now change the Wheel whenever we want. Here, the dependency ( wheel ) can be injected into Car at run time.

    After using dependency injection:

    Here, we are injecting the dependencies (Wheel and Battery) at runtime. Hence the term : Dependency Injection.

    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;
      }
    }
    

    Source: Understanding dependency injection

    链接地址: http://www.djcxy.com/p/252.html

    上一篇: Windows程序集堆和堆栈?

    下一篇: 什么是依赖注入?