This article is an overview of DIP, for an in-depth look at the Dependency Inversion Principle, you can read uncle Bob's article on DIP.
Defining Bad Design
If a software product is badly designed: it is rigid, fragile and immobile. So let's define those 3 properties, we can say that any software product:
- Is rigid if any change has multiple consequences.
- Is fragile if a single change results in unexpected bugs.
- Is immobile if we cannot easily extract parts of our system for reuse in other software products.
An Example Of Bad Design
Let's consider an example of bad design: we are going to model a system of a Button and a Lamp. Our
Button class can be switched on or off, when our
Button is switched on, the
Lamp is switched on and when the
Button is switched off, the
Lamp is switched off. Our
Button class uses the
Our code in the above example violates the Dependency Inversion Principle. As stated above, the Dependency Inversion Principle solves bad design. But we haven't defined the Dependency Inversion Principle, which can be stated as:
High level classes should not depend upon low level classes, both should depend on abstractions.
Abstractions should not depend on details, details should depend on abstractions.
At this point, we would want to know which classes are high level, and which are low level? In general, the class that uses another class is the high level class. So our
Button class is the high level class and the
Lamp class is the low level class.
How does our code in it's current iteration, not comply with the Dependency Inversion Principle:
Button class is dependant on the
- We cannot re-use the
Button class without also including the
- Any update, like creating a new class which needs to be turned on or off by our
Button cannot be added without modifying the
Button class itself.
How Do We Conform To The DIP?
For our code to conform with the Dependency Inversion Principle, we must invert the dependancies of our code:
Button must not depend on
Lamp, both must depend on abstractions (interfaces).
- We must be able to easily re-use
Button must not reference
Lamp now both depend on abstractions,
In General, How Do We Implement the Dependency Inversion Principle?
When we have
class A which is used by
We could abstract the methods used by
class B into an interface that is implemented by
Applying the same principle to
class B, i.e making
class B depend on an abstraction, so that any future version of our code which uses
class B will also depend on an abstraction, our code becomes:
- The Dependency Inversion Principle aims to remedy bad design resulting from rigidity, fragility and immobility.
- Classes that use other classes should both depend on abstractions and not directly on each other.
- The Dependency Inversion Principle in PHP can be implemented using interfaces.