2

During my career I only used DI to insert object of certain class based on certain interface. So there was never the situation when I needed two different bindings for one interface.

So natural question arises: can't I just use Concrete Factory instance of which I will create on compile time/runtime and use all over my code? What can be the other cases for DI?

For testing I would just use a different implementation of the Abstract Factory then check this pseudocode:

import concrete_factory from factories 
repository = concrete_factory.get_repository() 
repository.get_item() 
# factories.py 
if env == 'TEST': 
   concrete_factory = TestFactory() 
else: 
   concrete_factory = ProductionFactory() 
12
  • 6
    As the answer below states, a common use case is mocking during testing, but what I want to point out is that DI is, and should first and foremost be seen as, a component design approach, rather than some tool/gimmick/framework that we use as a convenience to automatically inject stuff. One of the major reasons for DI is the same as one of the major reasons you create functions with well-defined parameter lists (as opposed to grabbing some global out there) - to create well-defined, explicit interfaces between interacting components, and separate concerns. Sep 21, 2023 at 12:33
  • P.S. Your ConcreteFactory sounds a lot like the ServiceLocator pattern. Some people use it, but it's generally considered an antipattern. Sep 21, 2023 at 12:34
  • 3
    I really hope this questions reception improves because this is the sort of question this site needs. Sep 21, 2023 at 13:48
  • 2
    "I always thought that DI container uses Service Locator within itself" - DI and DI containers are separate things. DI is when you design your class to explicitly accept a dependency (regardless of how you inject it - manually, via a DI container). A DI container is a software tool that helps with that, and manages the lifetime of the dependencies. Now, it doesn't really matter that much what the DI container does internally, the issue people have with SvcLocator is when the component itself uses it internally to obtain a dependency, instead of letting something else inject it from the outside Sep 21, 2023 at 14:48
  • 1
    @FilipMilovanović It is entirely possible to abuse a DI container and treat it like a service locator. I measure that by counting the places in your code that know the DI container exists. You need at least 1 to get an object you can call start() on. That will get the object graph ticking. Each place after that one is giving you the same problems a service locator would. Sep 21, 2023 at 15:16

2 Answers 2

8

So there was never the situation when I needed two different bindings for one interface.

Polymorphism isn't the only reason to use Dependency Injection.

DI lets you control what knows about what. Statically knowing a class exists means you can't be deployed without that class. DI lets you sever that knowledge and make your code independently deployable.

Maybe that isn't an issue for you. Maybe you always deploy everything together. It can still be a useful conceptual boundary. What my class doesn't know about I don't have to think about. Least not while I'm here.

Maybe that isn't useful to you. Maybe you prefer to always know exactly what your class is talking to. In that case, go nuts. Use your service locator. Just understand the problems you're choosing to have. Either way there will be problems. It's nice to understand what you're choosing.

Also, DI sounds fancy but it's really just a new name for a very old idea. We used to just call it reference passing.

The biggest problem with a service locator is the reference grabbing. Now everything has an opinion about where stuff should be. Now nothing can be moved without updating everything that knows where it used to be. If you're fine with that service locator works as well as it ever did.

ServiceLocator finds implementation of interface on the runtime. On the other hand what I mean by ConcreteFactory is implementation of either TestFactory(mocked one) or ProductionFactory - cool_cat

In other words: injection allow to avoid global state since you can have multiple instances of Containers. Factory approach forces global state for whole application - cool_cat

So now everything everywhere is either mocked or it isn't? Sounds a bit extream.

I always thought that DI container uses Service Locator within itself - cool_cat

Structurally yes it does. But when done well a DI container does all its work in main (or whatever composition root). Everything all wired up before the object graph starts ticking. So no need to go asking for stuff because you've already been handed it.

8
  • Does a Service Locator stop being a Service Locator if your code communicates with service interfaces instead of concrete types, and you register your types with your interfaces at the aggregate root? Your services will still have to implement the interfaces, but you're code won't know anything about the implementation. Sep 21, 2023 at 13:24
  • 2
    Your last paragraph is finally how I understood DI containers. It takes building a non-trivial application to understand the benefits of having dependencies automatically handed to your constructors. Sep 21, 2023 at 13:30
  • 1
    Which I assume is why good DI containers generally provide a wealth of lifetime management options. Sep 21, 2023 at 13:38
  • 1
    It's also worth to note that one doesn't need a DI container to do DI. Depending on the project's size, complexity, and overall structure, a DI container can add more hassle than it solves.
    – T. Sar
    Sep 21, 2023 at 14:12
  • 2
    @T.Sar absolutely. Mark Seemann has dubbed this idea Pure DI. Not every good idea has to be enshrined in a framework. But if you do this by hand, please, have mercy. Sep 21, 2023 at 14:17
0

The other case is usually testing, where instead of injecting the real database or similar, you inject a mock object.

3
  • You can do that with "Factory" approach (check edited question) So it seems that dependency injection is only useful if you have 2 binding for the same Interface and you want to use those 2 binding on the same runtime, does this make sense?
    – cool_cat
    Sep 21, 2023 at 12:53
  • 1
    If you ever decide to modularize your code and ship part of it as a library, dependency injection will make that easier than relying on your specific service locator factory.
    – pjc50
    Sep 21, 2023 at 13:10
  • 1
    pjc50 thank you, also having option to inject dependency manually by passing ref into constructor/method seems beneficial and pure ServiceLocator approach would lack this possibility
    – cool_cat
    Sep 21, 2023 at 13:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.