I've done plenty of reading on Dependency Injection, but I have no idea, how does it actually reduce coupling?
The analogy I have of DI is that all components are registered with a container, so theyre are like in a treasure chest. To get a component, you obviously register it first, but then you would have to interrogate the treasure chest (which is like a layer of indirection). Is this the right analogy? It doesn't make obvious how the "injection" happens, though (how would that fit in with this analogy?).
Thanks
Dependency Injection is a form of a software design pattern that enables us to write loosely coupled code and reduces tight coupling among components. The tight coupling has strong dependencies that restrict code reuse. Dependency Injection enables us to reduce the coupling and helps us to write well maintainable code.
Dependency Injection is a technique that facilitates loosely coupled object-oriented software systems.
In this scenario, Spring Dependency Injection (DI) is a good choice. Spring can make your output generator loosely coupled to the output generator. Minor change in OutputHelper class. Create a Spring bean configuration file and declare all your Java object dependencies here.
A basic benefit of dependency injection is decreased coupling between classes and their dependencies. By removing a client's knowledge of how its dependencies are implemented, programs become more reusable, testable and maintainable.
Dependency Injection (DI) doesn't reduce coupling, per se, because the component that relies on the dependency is still coupled to its dependency. What DI does accomplish, however, is to remove the responsibility of finding the dependency from the component itself, and placing that responsibility elsewhere.
A component that relies on DI is completely passive when it comes to its dependencies. There is no code in the component that says "create a new instance of this dependency" or "go out and get me this dependency". The dependency is given to (injected into) the component, usually when the component itself is created by some other object.
This reversal of responsibility to create (or ask for creation of) a dependency is called Inversion of Control (IoC).
So, if the component doesn't know how to create or ask for a dependency, where does that responsibility lie? Usually in an object created specifically for dependency resolution, commonly called an IoC container. In your analogy, this is your "treasure chest". The IoC container contains the instructions that basically say "when somebody asks for this, give them one of these. An IoC container can typically inspect the component it's asked to create, figure out what its dependencies are, and create them too, walking down the "dependency chain" until all of the dependencies are resolved.
The big shift in thinking, the injection, comes when deciding *who gets to ask the container for the component's dependency"? Without DI, it would be the component itself that would ask the container for its dependency. Using DI, however, the responsibility of asking the container to "resolve" a component's dependency falls to whatever creates or uses the component. When the component is created, whatever is creating it has the responsibility of providing all of the dependencies. The component doesn't know or care how they are created, just that they are.
Now, if the dependency is defined as a concrete implementation, the component is still tightly coupled to that specific concrete implementation, even though it is being injected. DI itself does not reduce coupling in that sense. But if the dependency is defined as an interface, the component doesn't care or know what the concrete implementation is, nor how it's created. It's still coupled to the dependency, but it is a very loose coupling.
In that sense, "Dependency Injection" and "Programming to Interfaces" combine to create very loosely coupled, highly flexible components.
To go with your analogy of your components being in a treasure chest: A system (lets say a treasure polisher) without dependency injection has to have the ability to pick an item from the treasure chest itself. It has to have some knowledge the dependency's nature in order to pick the correct treasure to polish depending on the current context. Thus coupling.
In a DI scenario, your treasure polisher does not need to know about the existence of the treasure chest at all. All it needs to know is that at some point (preferably at creation) the polisher will be provided (injected) with an object which implements ITreasure
:
interface ITreasure
{
void PolishMe();
}
Thus your implementation class is de-coupled from your treasure chest.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With