Dependency Injection vs Service Locator – Key Differences Explained

dependency-injectionioc-containersservice-locator

I understand that directly instantiating dependencies inside a class is considered bad practise. This makes sense as doing so tightly couples everything which in turn makes testing very hard.

Almost all the frameworks I've come across seem to favour dependency injection with a container over using service locators. Both of them seem to achieve the same thing by allowing the programmer to specify what object should be returned when a class requires a dependency.

What's the difference between the two? Why would I choose one over the other?

Best Answer

When the object itself is responsible for requesting its dependencies, as opposed to accepting them through a constructor, it's hiding some essential information. It's only mildly better than the very tightly-coupled case of using new to instantiate its dependencies. It reduces coupling because you can in fact change the dependencies it gets, but it still has a dependency it can't shake: the service locator. That becomes the thing that everything is dependent on.

A container that supplies dependencies through constructor arguments gives the most clarity. We see right up front that an object needs both an AccountRepository, and a PasswordStrengthEvaluator. When using a service locator, that information is less immediately apparent. You'd see right away a case where an object has, oh, 17 dependencies, and say to yourself, "Hmm, that seems like a lot. What's going on in there?" Calls to a service locator can be spread around the various methods, and hide behind conditional logic, and you might not realize you have created a "God class" -- one that does everything. Maybe that class could be refactored into 3 smaller classes that are more focused, and hence more testable.

Now consider testing. If an object uses a service locator to get its dependencies, your test framework will also need a service locator. In a test, you'll configure the service locator to supply the the dependencies to the object under test -- maybe a FakeAccountRepository and a VeryForgivingPasswordStrengthEvaluator, and then run the test. But that's more work than specifying dependencies in the object's constructor. And your test framework also becomes dependent on the service locator. It's another thing you have to configure in every test, which makes writing tests less attractive.

Look up "Serivce Locator is an Anti-Pattern" for Mark Seeman's article about it. If you're in the .Net world, get his book. It's very good.

Related Topic