Why High‑Level Modules Should Depend on Abstractions: Mastering Dependency Inversion
This article explains the Dependency Inversion Principle, shows why traditional layered architectures suffer from maintenance and reuse problems, provides concrete Java and web examples, and demonstrates how refactoring to abstract interfaces resolves these issues for more flexible, decoupled software design.
Introduction
When developing with Spring, you can use features such as dependency injection and MVC without directly invoking Spring classes. This is possible because the application depends on abstractions defined by the framework, not on concrete framework implementations. The Dependency Inversion Principle (DIP) explains why.
Dependency Inversion Principle
DIP states that high‑level modules must not depend on low‑level modules; both must depend on abstractions. Moreover, abstractions must not depend on concrete implementations; concrete implementations depend on abstractions.
Issues in Traditional Layered Architecture
Maintenance difficulty : Changes in lower layers propagate upward, forcing modifications in higher‑level code.
Reuse difficulty : High‑level modules become tightly coupled to low‑level details, reducing their reusability.
Typical Examples of DIP in Practice
Database access: Application code depends on the java.sql.Connection / JDBC API, not on a specific driver. Swapping drivers requires no code change.
Web applications: Code depends on the Servlet API (J2EE specification) rather than on a concrete container such as Tomcat. Any compliant container can be used.
Design Guideline to Apply DIP
Each high‑level module should declare the abstract services it needs. Low‑level modules implement those abstractions. This reverses the dependency direction so that high‑level code never directly references concrete low‑level classes.
Concrete Refactoring Example: Button Controlling a Lamp
Original design (tight coupling):
public class Button {
private Lamp lamp;
public void poll() {
if (/* condition */) {
lamp.turnOn();
}
}
}Problems:
Button depends on the concrete Lamp class.
Any change to Lamp forces a change in Button.
Button cannot be reused to control other devices.
Refactored design using an abstraction:
public interface Switchable {
void turnOn();
void turnOff();
}
public class Lamp implements Switchable {
@Override public void turnOn() { /* … */ }
@Override public void turnOff() { /* … */ }
}
public class Button {
private final Switchable target;
public Button(Switchable target) {
this.target = target;
}
public void poll() {
if (/* condition */) {
target.turnOn();
}
}
}Now Button depends only on the Switchable abstraction, which is defined by the high‑level module. Any class that implements Switchable (e.g., a motor, a fan) can be controlled without modifying Button.
Broader Implications for Frameworks
Frameworks such as Spring and servlet containers follow the same pattern: the application implements framework‑provided interfaces (e.g., Servlet, ApplicationContextAware), and the framework invokes the application code. The application never calls framework internals directly.
Practical Guidelines
Prefer abstract interfaces or abstract classes over concrete implementations.
Define the abstraction in the high‑level module; let low‑level modules implement it.
Avoid inheriting from concrete classes unless they are designed as abstractions.
Do not override methods that contain concrete business logic; instead, extend the abstraction.
When designing a framework, expose core functionality through interfaces and let client code provide implementations.
References
Dependency Inversion Principle – https://flylib.com/books/en/4.444.1.71/1/
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
JavaEdge
First‑line development experience at multiple leading tech firms; now a software architect at a Shanghai state‑owned enterprise and founder of Programming Yanxuan. Nearly 300k followers online; expertise in distributed system design, AIGC application development, and quantitative finance investing.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
