CSC/ECE 517 Fall 2009/wiki3 5 SD
Dependency inversion principle
Introduction
In conventional application architecture, lower-level components are designed to be consumed by higher-level components which enable increasingly complex systems to be built. In this composition, higher-level components depend directly upon lower-level components to achieve some task. This dependency upon lower-level components makes applications rigid, fragile and immobile. Goal of Dependency inversion principle is to decouple the high-level components from low-level components.
What is Dependency inversion principle?
Dependency inversion principle states that:
- 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.
Examples
Pictorial Example: Consider the following block diagram. Here the higher level class, Dinner depends upon the lower level classes Turkey and Stuffing.
Now, if we want to make Chicken instead of Turkey for dinner then the Dinner class becomes useless since it cannot be used in any other context other than making Turkey and Stuffing.
Notice that the module containing the high level policy, i.e. the Dinner() module, is dependent upon the low level detailed modules that it controls. (i.e. Turkey() and Stuffing()). If we could find a way to make the Dinner module independent of the details that it controls, then we could reuse it freely.
Consider the modified class diagram shown here:
Here we have a Dinner class which contains an abstract Meat class and an abstract Sauce class. Now we can have a loop within the Dinner class that gets ingredients from its abstract classes. Yet the Dinner class does not depend upon the “Turkey” nor the Stuffing class at all. Thus the dependencies have been inverted. Now we can reuse the “Dinner” class, independently of the “Turkey” and the “Stuffing” class.
Pictorial example along with code
Consider the following block diagram. The higher level module Copy() depends upon lower level modules ReadUI() and WriteScreen().
The code for the above diagram would look like this:
Void Copy { ReadUI() Writescreen() }
Notice that the two lower modules ReadUI() and WriteScreen() are reusable where as the higher level module Copy() cannot be reused in any other context other than Reading from a UI and Writing to a screen. This is a little inconvinient because there might be some useful logic in Copy() that could have been used to say Write to a file instead to the screen.
By reversing the dependencies as shown below we can reuse the Copy() module:
class Reader { public: virtual int Read() = 0; }; class Writer { public: virtual void Write(char) = 0; }; void Copy(Reader& r, Writer& w) { int c; c = r.Read() w.Write(c); }