The DIP states:
- High-level modules should not depend on low-level modules. Both should depend on abstractions.
- Abstractions should not depend upon details. Details should depend upon abstractions.
And the OCP states:
Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.
I think if we satisfy the DIP, it will cover the OCP too, So, why we separate these two principles?
Dependency Injection is an implementation technique for populating instance variables of a class. Dependency Inversion is a general design guideline which recommends that classes should only have direct relationships with high-level abstractions.
The Single Responsibility Principle — Classes should have a single responsibility and thus only a single reason to change. The Open/Closed Principle — Classes and other entities should be open for extension but closed for modification. The Liskov Substitution Principle — Objects should be replaceable by their subtypes.
The Dependency Inversion Principle (DIP) states that high level modules should not depend on low level modules; both should depend on abstractions. Abstractions should not depend on details.
Martin. DIP is basically the idea that high-level modules/implementations should not depend on lower level modules/implementations. If that is the case — that our high-level modules depend on lower level modules means that there is an inversion of dependencies! Hence the name of the principle.
Uncle Bob Martin, who popularized the Open-Closed Principle (OCP) and Dependency Inversion Principles (DIP) as two of the SOLID principles, states himself that DIP arises from an application of OCP and the Liskov Substitution Principle:
In this column, we discuss the structural implications of the OCP and the LSP. The structure that results from rigorous use of these principles can be generalized into a principle all by itself. I call it “The Dependency Inversion Principle” (DIP).
Robert C. Martin, Engineering Notebook, C++ Report, 1996.
So you're right in stating that every instance of DIP will be an instance of OCP, but OCP is much more general. Here's a use-case of OCP but not DIP I ran into recently. Many web frameworks have a notion of signals, where upon one action, a signal is fired. The object sending the signal is completely unaware of the listeners who are registered with the signal. Every time you want to add more listeners to the signal, you can do so without modifying the sender.
This is clearly exemplifying OCP ("closed to modification, open for extension"), but not DIP, as the sender is not depending on anything, so there's no sense in talking about whether it depends on something more abstract or less so.
More generally you can say the Observer Pattern (one of the GoF patterns) describes how to comply with OCP but not DIP. It'd be interesting to go through the GoF book and see which ones have to do with OCP and how many of those are not DIP-related.
I think adhering to the DIP makes it easier to comply with the OCP. However, one does not guarantee the other.
For example, I can create a class that has a method that takes a parameter of base
. If base
is an abstract class then I'm adhering to the DIP as I have inverted the dependency to the caller. However, if the code in that method does something like:
if (base is derived)
(derived)base.DoSomethingSpecificToDerived;
elsif (base is evenMoreDerived)
(evenMoreDerived)base.DoSomethingSpecificToEvenMoreDerived;
Then it's not OCP compliant as I have to modify it every time I add a new derivative.
It's very contrived example, but you get my point.
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