Loose Coupling & Dependency Inversion Principle (DIP)
1Concept
The Dependency Inversion Principle (SOLID) states: High-level modules should not depend on low-level modules; both should depend on abstractions. Designing components against interfaces rather than concrete classes achieves loose coupling and seamless testability (mocking).
2Architecture Diagram
Tightly Coupled: [ OrderService ] ---> [ PostgresDatabase ] (Rigid! Cannot swap or mock) Loosely Coupled: [ OrderService ] ---> [ DataRepository Interface ] <--- [ Postgres / Mongo / Mock ]
3Code Example
Core Java
public class DependencyInversionDemo {
// Abstraction contract
interface MessageSender {
void sendMessage(String recipient, String message);
}
// Concrete Low-level implementation
static class SmtpMailSender implements MessageSender {
public void sendMessage(String recipient, String message) {
System.out.println("SMTP mail sent to " + recipient + ": " + message);
}
}
// High-level service depending strictly on abstraction
static class NotificationCoordinator {
private final MessageSender sender;
// Injected via constructor (Dependency Injection)
public NotificationCoordinator(MessageSender sender) {
this.sender = sender;
}
public void notifyUser(String user) {
sender.sendMessage(user, "Security Alert: New login from unknown IP");
}
}
public static void main(String[] args) {
MessageSender emailSender = new SmtpMailSender();
NotificationCoordinator coordinator = new NotificationCoordinator(emailSender);
coordinator.notifyUser("admin@enterprise.com");
}
}4Expected Output
SMTP mail sent to admin@enterprise.com: Security Alert: New login from unknown IP
5Key Takeaways
- ✓Always code to interfaces, not concrete implementations.
- ✓Dependency injection facilitates frictionless unit testing using mock frameworks (Mockito).
- ✓Loose coupling minimizes regression blast radius when swapping infrastructure components.