views:

894

answers:

4

Both patterns seem like an implementation of the principle of inversion of control. That is, that an object should not know how to construct its dependencies.

Dependency Injection (DI) seems to use a constructor or setter to "inject" it's dependencies.

Example of using Constructor Injection:

//Foo Needs an IBar
public class Foo
{
  private IBar bar;

  public Foo(IBar bar)
  {
    this.bar = bar;
  }

  //...
}

Service Locater seems to use a "container", which wires up its dependencies and gives foo it's bar.

Example of using a Service Locator:

//Foo Needs an IBar
public class Foo
{
  private IBar bar;

  public Foo()
  {
    this.bar = Container.Get<IBar>();
  }

  //...
}

Because our dependencies are just objects themselves, these dependencies have dependencies, which have even more dependencies, and so on and so forth. Thus, the Inversion of Control Container (or DI Containor) was born. Examples: Castle Windsor, Ninject, Structure Map, Spring, etc.)

But a IOC/DI Container looks exactly like a Service Locator. Is calling it a DI Containor a bad name? Is an IOC/DI Container just another type of Service Locator? Is the nuance in the fact that we use DI Containers mostly when we have many Dependencies?

+7  A: 

When you use a service locator, every class will have a dependency on your service locator. This is not the case with dependency injection. The dependency injector will typically be called only once at startup to inject dependencies into some main class. The classes this main class depends on will recursively have their dependencies injected, until you have a complete object graph.

A good comparison: http://martinfowler.com/articles/injection.html

If your dependency injector looks like a service locator, where the classes call the injector directly, it is probably not a dependency injector, but rather a service locator.

Joel
+12  A: 

The difference may seem slight, but even with the ServiceLocator, the class is still responsible for creating its dependencies. It just uses the service locator to do it. With DI, the class is given it's dependencies. It neither knows, nor cares where they come from. One important result of this is that the DI example is much easier to unit test -- because you can pass it mock implementations of its dependent objects. You could combine the two -- and inject the service locator (or a factory), if you wanted.

tvanfosson
Additionally, you can use both when constructing a class. The default constructor can use the SL to retrieve the dependencies, and pass them to the "real" constructor which receives those dependencies. You get the best of both worlds.
Grant Palin
No, the ServiceLocator is the one responsible for instantiating the correct implementation for a given dependency (plugin). In the case of DI, the DI "container" is the one responsible for that.
Rogerio
+4  A: 

Service locators hide dependencies - you can't tell by looking at an object whether it hits a database or not (for example) when it obtains connections from a locator. With dependency injection (at least constructor injection) the dependencies are explicit.

Moreover, service locators break encapsulation because they provide a global point of access to dependencies of other objects. With service locator, as with any singleton:

it becomes difficult to specify the pre and post conditions for the client object's interface, because the workings of its implementation can be meddled with from outside.

With dependency injection, once an object's dependencies are specified, they are under control of the object itself.

Jeff Sternal
I prefer "Singletons Considered Stupid", http://steve.yegge.googlepages.com/singleton-considered-stupid
Charles Graham
I love ol' Steve Yegge and the title of that article is great, but I think the article I cited and Miško Hevery's "Singletons are Pathological liars" (http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/) make a better case against the particular devilry of service locator.
Jeff Sternal
+2  A: 

A class using constructor DI indicates to consuming code that there are dependencies to be satisfied. If the class uses the SL internally to retrieve such dependencies, the consuming code is not aware of the dependencies. This may on the surface seem better, but it is actually helpful to know of any explicit dependencies. It is better from an architectural view. And when doing testing, you have to know whether a class needs certain dependencies, and configure the SL to provide appropriate fake versions of those dependencies. With DI, just pass in the fakes. Not a huge difference, but it is there.

DI and SL can work together, though. It is useful to have a central location for common dependencies (e.g. settings, logger, etc). Given a class using such deps, you can create a "real" constructor that receives the deps, and a default (no parameter) constructor that retrieves from the SL and forwards to the "real" constructor.

EDIT: and, of course, when you use the SL, you are introducing some coupling to that component. Which is ironic, since the idea of such functionality is to encourage abstractions and reduce coupling. The concerns can be balanced, and it depends on how many places you would need to use the SL. If done as suggested above, just in the default class constructor.

Grant Palin