Section 10.8 Dependency Inversion
Related to all these ideas of interfaces and decoupling is another important idea, called dependency inversion. In essence this concept is about two different dependencies:
A module (think class/file)Ahas a runtime dependency on moduleBif when the program runs there is transfer of control from the code inAto that inB, typically via a function call.A moduleAhas a source code dependency or compile time dependency on moduleBwhen the source code ofAdirectly references the source code ofB.
As an example of these concepts, consider the
GradeReader and Summary classes. When the program executes by running Main, an instance of the Summary class is created, and it is given an instance of the GradeReader class as a parameter. It then calls that classβ hasNext() and next() methods (or the original hasMoreEntries() and processNextGradeRow() names). At that point in time the code execution moves from Summary to GradeReader via the function call, resulting in a runtime dependency from Summary to GradeReader.
On the other hand, there is no source code dependency between the two classes. Instead they both depend on the
Iterator interface. Before we had that interface, the Summary class had a parameter of type GradeReader and there was a source code dependency from Summary to GradeReader. The use of the interface allowed us to break that source code dependency. This is dependency inversion:
Dependency Inversion occurs when the source code dependency between two modules opposes their runtime dependency. This is done by the use of an interface on which both modules depend.Dependency inversion is essential for the health of a software, because it allows us to independently develop and test the two modules.
A deeper reason has to do with the so-called Dependency Inversion Principle, that we will look at more closely at a later time. (TODO: Dependency Inversion Principle link)
