DIP:
-
- A. High level modules should not depend upon low level modules. Both should depend upon abstractions.
-
- B. Abstractions should not depend upon details. Details should depend upon abstractions. (http://www.objectmentor.com/resources/articles/dip.pdf)
Forces
We wish to avoid designs which are:
- Rigid (Hard to change due to dependencies. Especially since dependencies are transitive.)
- Fragile (Changes cause unexpected bugs.)
- Immobile (Difficult to reuse due to implicit dependence on current application code.)
Inversion
"Structured" methods of the 1970's tended towards a "top-down decomposition", which
encouraged high-level modules to depend on modules written at a lower level of abstraction. (More modern procedural approaches depend more on databases and less on functional decomposition at the large-scale level. Thus, they are often "flatter" now.) This principle stems from the realization that we must reverse the direction of these dependencies to avoid
rigidity, fragility and
immobility. [edited from Robert's original to reflect modern procedural philosophy]
Examples
In
RobertMartins article, he uses a simple copying program as an example. The program copies characters from the keyboard to a printer. Modifying the program to support arbitrary output devices is inelegant since the copy "routine" implicitly depends on the keyboard reading code. A better architecture would define interfaces for readers and writers, thus the program can be easily adapted to support reading and writing from additional code for new devices.
(This example seems to explain some of the idioms present in the java.io package.)
The Observer design pattern can be considered a two-layered architecture,
where the model is the lower-level module and the higher level module is the observer.
See also:
- [Martin95] Robert C. Martin, Object Oriented Design Quality Metrics: An Analysis of dependencies, ROAD, Vol. 2, No. 3, Sep-Oct, 1995.
- This principle occurs as a result of the OpenClosedPrinciple and the LiskovSubstitutionPrinciple.
- AclassIsNothingButaCyclicDependency
- [Martin2002] Robert C. Martin, Agile Software Development: Principles, Patterns, and Practices, p.127-135
One of the
PrinciplesOfObjectOrientedDesign.
Controversies
Some of this sounds like typical pro-OO procedural-bashing. The "device driver" examples may not extrapolate to all situations and assume that adding new devices is more common than adding new operations to existing devices (
ExtrapolatingDeviceDrivers). What is "rigid" often depends on assumed
ChangePatterns. There is no free lunch in such cases, only estimations of paths of least costs.
And, too many layers of indirection is sometimes anti-
YagNi.
In practice, what you mean by "dependency" will depend on the language. In Smalltalk, whatever handful of messages the client happens to send to a server is a protocol implicitly. It doesn't have to be named to satisfy the type checker. The client has no dependency on the server beyond them. So inserting the abstract base class buys you very little. You might as well just group the messages together in the IDE and label them there without adding the new class.
In C++, the traditional C++ and link formats mean that client code can depend on the size of the server object, the layout of its vtbl, and many other incidental details. The abstract base class is a way of making these details more stable.
It seems to me that the dependencies the inversion principle are trying to avoid are just artifacts of premature optimisation in the language implementation. --
DaveHarris
Circular dependencies between
VisualBasic projects are worse than a nuisance -- they prevent you from being able to build executables from sources.
Specific examples?
Proper application of the
DependencyInversionPrinciple -- via implementation of VB/COM interfaces -- resolves the problem.
Alternative for
VisualBasic:
Use "As Object" (IDispatch interface).
Doing so will remove compile-time circular dependencies, at the expense of type safety and compile time type checking.
(The projects will depend on IDispatch, rather than referencing each other.)
See also
DependencyInversionAndXp and
ContextIndependence
CategoryModellingLawsAndPrinciples