What is a Dependency
For the purposes of this discussion a class A has a dependency on another class B, iff you cannot compile class A without class B.
Example
class A {B b;} class B { } |
We have to compile class B before (or at the same time as) class A.
Other kinds of Dependency
Anywhere the name “B” appears in class A creates a dependency. Some other examples of dependencies are:
class A extends B { } class A implements B { } class A { void method(B b) { } } |
Transitive Dependencies
If a class A depends on another class B which itself has dependencies then the dependencies of class B are effectively dependencies of class A
Example:
class A { B b; } class B { C c; } class C { } |
We have to compile class C before (or at the same time as) class B and class A.
The Problem
When class C changes, we have to recompile and retest both class A and class B. In a large system this can take a very long time. It also means that you have to know about class C in advance; you cannot decide on class C after deciding on class A.
If class C is a more concrete class then it might change more frequently than class A. This will cause class A to be recompiled/tested much more frequently than it otherwise would need to be.
The Solution
Inverting Dependencies
Have class A and class B both depend on an abstraction I. This inverts the direction of the dependency arrow on class B.
interface I { } class A { I i; } class B implements I { } |
Breaks Transitive Dependency
The really helpful effect of this inversion is that it also breaks the transitive dependency from class A onto class B
interface I{ } class A { I i; } class B implements I{ C c; } class C { } |
Dependency Inversion Principle
This is an application of the Dependency Inversion Principle:
- 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.


Pingback: » Compilation Time and Layering Lexical Scope