5

I just read documentation and tutorial about dependency injection (DI) and the singleton pattern (SP). Everybody seems to says DP is bad and DI is the way to do it. Tutorials about dependency injection use some framework like Autofac or Ninject. They also all explain DI don't need a framework, container. I understand.

Actually DI is not complicate. You create an interface then you pass the implementation of your interface to the constructor.

But always come the moment where they explain that with Autofac or Ninject or other container you must define the lifetime of you class. So you have this line

kernel.Bind<MyFacade>.To<MyFacade>().InSingletonScope(); 

And again yes. DI is simple but in the simple version of DI there is no Singleton. So when you want to use DI for singleton behavior you must use a container, right? So at the end the container is just managing the single stuff for you, right?

So DI is not something we should oppose to SP. DI with container is something I can oppose to SP.

So at the end why I should not use SP by myself but trust a library to do it? What is the difference between DI using container with single scope and SP?

11
  • You can use one, the other, or both combined. No surprise there. I will remind you that using a library is adding a dependency. We got to decide if we are going to treat it like an external system or not. I do not know how people would usually justify it. However, I guess that if you are going to tie your code to a particular library, having a singleton is no big deal.
    – Theraot
    Jun 30, 2019 at 1:42
  • Yes. This is my secret argument. What is the real benefit of DI when to perform you must use container that, in fact, adding another dependency. What is the point to do DI to avoir dependency by adding a new one from you libraries. So what should I think about all these peopl telling me un must use DI end always avoir singleton? Jul 1, 2019 at 2:37
  • I have no solution for you, just this: public singletons are bad, they are effectively globals. Dependency injection is is good, for instance it makes testing easier, but is not the only alternative. Similarly there are alternatives to containers, but depending what you are doing, you might want them. In fact, you might want to inject sigletons! (not public and with strong concurrency guarantees, but singletons). So, no, having singletons is not the problem, it is how you use them. I suspect the same is true for the DI container. We can keep wishing for a pattern that prevents being abused.
    – Theraot
    Jul 1, 2019 at 4:09
  • Is everything coming from your web.config file also wrong then? This config file is also kind of global variable. We should not use it? Jul 1, 2019 at 4:12
  • That is a good example. Yes you need it, and on the other hand you are better of isolating from it. Wrap it in something you can pass around or inject, that way you can run tests agasint your code under different configurations. Notice that, although I said that public singletons are bad, I am not saying that you should eliminate them or avoid them. That would be like asking for a C program to not use standard input and output, or javascript code to never access the DOM. I'm not that purist. Some part of you code deals with that kind of things, and abstract them to terms you control.
    – Theraot
    Jul 1, 2019 at 4:29

3 Answers 3

3

You're correct that the idea of DI is to be able to rely on an abstraction (interface) rather than a concrete implementation, but that is only one piece of the puzzle. You still need to instantiate the actual object somewhere else, before passing in to a constructor or injecting it. The bigger part here is how you create that instance. Since simply new-ing up the object still keeps you tied to that specific implementation, it's recommended instead to use a pattern such as a factory. Using a DI container just makes it easier and allows us to not reinvent the wheel, but of course you can do whatever suits your needs best.

Now, if you only have a couple classes or a small project, then maybe just using the singleton pattern on your own is perfectly acceptable. It all comes down to preference.

3
  • 1
    allows us to not reinvent the wheel - exactly what every new DI container does ;)
    – Fabio
    Jul 1, 2019 at 2:23
  • @Fabio The difference between allowing and forcing ;-) Jul 9, 2019 at 19:22
  • 1
    I've done DI with and without containers. If you do it properly, without letting clients know what DI container your using or employing a service locator, the benefit of the container boils down to encouraging the separation of construction code and behavior code (a good thing) by having you do construction in a different language (a dubious thing). Such as xml. You love xml right? Jul 12, 2019 at 22:30
7

So you need to construct something once only. Fine. Have access to main? Great. Build it in main once. Main is only called once. Pass it to everything that needs it. Call that passing "dependency injection" if it makes you feel fancy. Done.

Don't have access to main because you're using some annoying framework? Find any method that is called once and only once. Use that as your "composition root". It's usually found as high up the call stack as you can get.

Don't have access to a method that is only called once? Well like it or not, now you're stuck with the singleton pattern. It works as well as it ever did. This isn't it's fault. You're just stuck in a crappy situation. Maybe stop using crappy frameworks.

2
  • I love the way you give both good advice here and still nod you head to pragmatism, without endorsing it. +1
    – David Arno
    Jul 1, 2019 at 7:50
  • 1
    Am I asking a question or leaving a comment? Yes. Do I enjoy Socratic Method answers? Absolutely. Jul 9, 2019 at 16:55
6

Singletons pattern generally refers to a single global instance. I.e. a static property in c#. Most of the problems with this is related to the "global" part, or more specifically, the combination of "global" and "mutable".
This question goes into the problems with singleton pattern in more details

So when you want to use DI for singleton behavior you must use a container, right?

No, you may still design your application with only one instance of a class, simply create it in the main method and inject it to all who needs it. This avoids most of the problems with SP, but you still have only one object. This works just the same as using a DI container, except you need to manage the creation yourself.

Also note that "singleton" lifetime with regards to DI containers means that there is one instance of a class per container, and that this instance lives at most as long as the container. This is different from SP since there is nothing "global" about this.

So at the end the container is just managin the single stuff for you, right?

No, you can still use the container to create objects with shorter lifetimes than the container. I might for example have a logging object registered as a singleton, but resolve multiple instances of a class that depends on this logger.

So DI is not something we should oppose to SP. DI with container is something I can oppose to SP.

This seem opinion based, but from my point of view they are quite opposite. SP hides dependencies, DI makes them clearer. SP makes it more difficult to replace or mock dependencies, DI makes it trivial.

So at the end why I should not use SP by myself but trust a library to do it?

As previously mentioned, you do not need a library to use DI, even if it makes it easier. I would personally trust a library used by thousands more then I trust my own code.

What is the difference between DI using container with single scope and SP?

You avoid most of the issues with SP for a start.

As an example, consider a application that connects to a database, where the database connection is in a global singleton. This might work fine, but consider if the requirements change so that it should be possible to connect to multiple databases, each with a separate window or view. SP makes such a change almost impossible since every class that uses the database must now know which database to use.

If a DI container is used, this can be almost trivial, simply create another container object in the same way you created the first one, but with a different connection string. Only the code that directly deals with loading or selecting databases need to know there are several of them. Other objects do not need to change, because in the context of the DI container they live in, there is still only one database.

4
  • This is different from SP since there is nothing "global" about this. But how do I access the container? Isn't the container necessarily global?
    – scenia
    Oct 13, 2020 at 8:04
  • Not necessarily. You would typically have a container for each application "context", where the context creates and initializes the container. But you could have multiple instances of the application in the same process. And it should be fairly easy to change from single to multiple instances. You can also have multiple levels. For example, you could have one "global" container, 0..n containers for text documents, 0..n containers for spreadsheets etc.
    – JonasH
    Oct 13, 2020 at 9:48
  • Thanks for the reply, I think I got it now. Basically, nothing actually needs a reference to the container as long as the container (or main, which can just initialize the container and then has a reference) is the one that instantiates everything as needed. Right?
    – scenia
    Oct 13, 2020 at 14:56
  • @scenia yes, thats it. There may be exceptions for things like factories, if something need to create multiple instances of some type from the container. UnityContainer allows the container itself to be injected as a dependency, but that should be avoided if possible.
    – JonasH
    Oct 13, 2020 at 15:02

Your Answer

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

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