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