Dependency Inversion Principle (DIP)
Definition
High-level modules should not depend on low-level modules.
Both should depend on abstractions.
👉 Depend on interfaces/abstractions, not concrete classes.
Purpose
- Reduce tight coupling
- Improve flexibility
- Enable dependency injection
- Make unit testing easier
- Build scalable architecture
Bad Example ❌
Low-Level Class
public class SqlRepository
{
public void Save()
{
Console.WriteLine("Saved to SQL");
}
}
High-Level Class
public class InvoiceService
{
private readonly SqlRepository _repository =
new SqlRepository();
public void CreateInvoice()
{
_repository.Save();
}
}
Problem
InvoiceService directly depends on:
SqlRepository
If database changes:
- MongoDB
- PostgreSQL
- MySQL
👉 High-level code must change.
This creates:
- Tight coupling
- Difficult testing
- Poor scalability
Good Example ✅
Step 1: Abstraction
public interface IRepository
{
void Save();
}
Step 2: Low-Level Implementation
public class SqlRepository : IRepository
{
public void Save()
{
Console.WriteLine("Saved to SQL");
}
}
Another Implementation
public class MongoRepository : IRepository
{
public void Save()
{
Console.WriteLine("Saved to MongoDB");
}
}
Step 3: High-Level Module
public class InvoiceService
{
private readonly IRepository _repository;
public InvoiceService(IRepository repository)
{
_repository = repository;
}
public void CreateInvoice()
{
_repository.Save();
}
}
Usage Example
IRepository repository =
new SqlRepository();
var service =
new InvoiceService(repository);
service.CreateInvoice();
Output
Saved to SQL
Key Concept
Instead of:
Service → SQL Repository
We do:
Service → Interface ← Repository
👉 Loose coupling achieved.
Real-Time Scenario
Payment System:
IPaymentGateway
↓
Stripe
PayPal
Razorpay
👉 Change providers without changing business logic.
Advantages
- ✔ Loose coupling
- ✔ Easier testing/mock support
- ✔ Better scalability
- ✔ Flexible architecture
- ✔ Easier maintenance
Disadvantages
- ✖ More interfaces/classes
- ✖ Slightly increased abstraction complexity
When to Use
Use DIP when:
- Building enterprise applications
- Using dependency injection
- External systems may change
- Unit testing is important
- Scalability is required
Real Project Mapping (.NET + Angular)
| Feature | DIP Usage |
|---|---|
| Repository pattern | DIP |
| Service injection | DIP |
| Payment gateways | DIP |
| Notification providers | DIP |
| File storage providers | DIP |
ASP.NET Core Real Example
Dependency Injection Container
builder.Services.AddScoped<
IRepository,
SqlRepository>();
👉 ASP.NET Core DI is built around DIP.
Unit Testing Example
var mockRepo = new Mock<IRepository>();
👉 Easy mocking because of abstraction.
DIP vs OCP
| DIP | OCP |
|---|---|
| Depend on abstractions | Extend without modifying |
| Focus on dependencies | Focus on extensibility |
| Achieves loose coupling | Achieves scalability |
Common DIP Violation Signs
- new Keyword inside services
- Direct database dependency
- Hardcoded implementations
- Difficult unit testing
Pro Tip
DIP works best with:
- Dependency Injection
- Repository Pattern
- Strategy Pattern
- Clean Architecture
- Microservices
Summary
DIP helps you:
- Reduce tight coupling
- Depend on abstractions
- Build scalable systems
👉 Perfect for:
- Enterprise applications
- APIs
- Microservices
- Testable architectures
Comments
Post a Comment