If you look at your three definitions, the distinction is subtle, but they essentially mean the same thing.
What it all amounts to is providing what the class needs (its dependencies) through parameters in it's constructor. That's all. There are numerous Dependency Injection frameworks out there that seek to formalize this process, but they all amount to the same thing.
Dependency Injection always seeks to provide only those dependencies that are needed, when they are needed.
Constructor Injection has the advantage that it makes the dependency explicit and forces the client to provide an instance. It can also guarantee that the client cannot change the instance later. One (possible) downside is that you have to add a parameter to your constructor.
Setter Injection has the advantage that it doesn't require adding a parameter to the constructor. It also doesn't require the client to set the instance. This is useful for optional dependencies. This may also be useful if you want the class to create, for example, a real data repository by default, and then in a test you can use the setter to replace it with a testing instance.
Interface Injection, as far as I can tell, is not much different than setter injection. In both cases you are (optionally) setting a dependency that can be changed later.
Ultimately it is a matter of preference and whether or not a dependency is required. Personally, I use constructor injection almost exclusively. I like that it makes the dependencies of a class explicit by forcing the client to provide an instance in the constructor. I also like that the client cannot change the instance after the fact.
Often times, my only reason for passing in two separate implementations is for testing. In production, I may pass in a DataRepository
, but in testing, I would pass in a FakeDataRepository
. In this case I'll usually provide two constructors: one with no parameters, and another that accepts a IDataRepository
. Then, in the constructor with no parameters, I will chain a call to the second constructor and pass in a new DataRepository()
.
Here's an example in C#:
public class Foo
{
private readonly IDataRepository dataRepository;
public Foo() : this(new DataRepository())
{
}
public Foo(IDataRespository dataRepository)
{
this.dataRepository = dataRepository;
}
}
This is known as Poor Man's Dependency Injection. I like it because in production client code, I don't need to repeat myself by having several repeated statements that look like
var foo = new Foo(new DataRepository());
However, I can still pass in an alternate implementation for testing. I realize that with Poor Man's DI I'm hardcoding my dependency, but that's acceptable for me since I mostly use DI for testing.
Best Answer
Definitions
Inversion of control is a design paradigm with the goal of reducing awareness of concrete implementations from application framework code and giving more control to the domain specific components of your application. In a traditional top down designed system, the logical flow of the application and dependency awareness flows from the top components, the ones designed first, to the ones designed last. As such, inversion of control is an almost literal reversal of the control and dependency awareness in an application.
Dependency injection is a pattern used to create instances of classes that other classes rely on without knowing at compile time which implementation will be used to provide that functionality.
Working Together
Inversion of control can utilize dependency injection because a mechanism is needed in order to create the components providing the specific functionality. Other options exist and are used, e.g. activators, factory methods, etc., but frameworks don't need to reference those utility classes when framework classes can accept the dependency(ies) they need instead.
Examples
One example of these concepts at work is the plug-in framework in Reflector. The plug-ins have a great deal of control of the system even though the application didn't know anything about the plug-ins at compile time. A single method is called on each of those plug-ins, Initialize if memory serves, which passes control over to the plug-in. The framework doesn't know what they will do, it just lets them do it. Control has been taken from the main application and given to the component doing the specific work; inversion of control.
The application framework allows access to its functionality through a variety of service providers. A plug-in is given references to the service providers when it is created. These dependencies allow the plug-in to add its own menu items, change how files are displayed, display its own information in the appropriate panels, etc. Since the dependencies are passed by interface, the implementations can change and the changes will not break the code as long as the contract remains intact.
At the time, a factory method was used to create the plug-ins using configuration information, reflection and the Activator object (in .NET at least). Today, there are tools, MEF for one, that allow for a wider range of options when injecting dependencies including the ability for an application framework to accept a list of plugins as a dependency.
Summary
While these concepts can be used and provide benefits independently, together they allow for much more flexible, reusable, and testable code to be written. As such, they are important concepts in designing object oriented solutions.