A relation between Dependency Injection, single instance, and singletons

dependency-injection

I read So Singletons are bad, then what? which was a great explanation of dependency injection as the solution for inversion of control. The asker assumed singleton and single instance were synonyms, and as others pointed out singleton is a more restrictive example of single instance.

My question is, why did the responder go from single instance to talking about dependency injection? He states:

A cache does not need to be a singleton. It may need to be a single instance if you want to avoid fetching the same data for multiple cache instances; but that does not mean you actually have to expose everything to everyone.

With DI, you have one interface, in this case "Cache". However, you have multiple instances. Instances of VideoPage + instances of MyAccountPage + etc. VideoPage implements IMediaCache which extends Cache. The DI is that the dependent class that makes use of this caching abstraction does so by using the Cache interface as a type in a parameter list (parameter list of constructor if using constructor injection, etc.)

So there are multiple instances (x VideoPages, y MyAccountPages, etc.) The Cache is the "single" thing in this design pattern, but it's not an instance since you can't instantiate an interface.

"Single instance" and "Dependency Injection" to me are separate ideas, so that response confused me.

I also don't know why people saying dependency injection is an alternative to singletons. A singleton forces one instance even if I try to instantiate again. As for dependency injection, again, what is my "single instance"? The Cache isn't, as I explained earlier. And there are multiple instances of classes ultimately implementing the Cache interface.

Best Answer

Because dependency injection container can and is used for lifetime management. Basically, singleton's main purpose is to maintain lifetime of exactly one instance : it is created once at startup (or first use) and is destroyed when application ends. But if you put both lifetime management and behavior itself in single class (eg. singleton), you break single responsibility principle.

On the other hand, if you have a single top container and use it to manage lifetime of that one instance, based on interface. You can tell you DI container to handle that one implementation of interface as a singleton. So it returns same instance every time it is requested. There are also different lifetimes : per-thread, per-(web)request, etc..

If you use DI instead of static field, then design around this single instance becomes much cleaner. It will also make it easier to change your mind later on, if you realize that what you first thought was a singleton actually isn't.