Dependency Inversion Principle (DIP)
Dependency Inversion Principle (DIP)
The Dependency
Inversion Principle states: High-level modules should not
depend on low-level modules. Both should depend on abstractions. Also, abstractions
should not depend on details; details should depend on abstractions.
Real-Time Example: Notification System
Imagine
an application that needs to send notifications (email, SMS, etc.).
Violates DIP (Tightly Coupled Design):
public class NotificationService
{
private readonly EmailSender emailSender =
new EmailSender();
public void Notify(string message)
{
emailSender.SendEmail(message);
}
}
public class EmailSender
{
public void SendEmail(string message)
{
Console.WriteLine($"Email
sent: {message}");
}
}
Here, NotificationService directly
depends on the concrete class EmailSender. This tight coupling makes
it hard to test, extend, or replace (e.g.,
with SmsSender).
Follows DIP (Loosely Coupled Design):
Introduce
an abstraction:
public interface INotifier
{
void Send(string message);
}
Implement
different types of notifiers:
public class EmailSender : INotifier
{
public void Send(string message)
{
Console.WriteLine($"Email:
{message}");
}
}
public class SmsSender : INotifier
{
public void Send(string message)
{
Console.WriteLine($"SMS:
{message}");
}
}
Inject
the dependency:
public class NotificationService
{
private readonly INotifier notifier;
public NotificationService(INotifier
notifier)
{
this.notifier =
notifier;
}
public void Notify(string message)
{
notifier.Send(message);
}
}
Now, NotificationService depends
on an abstraction (INotifier), not a specific class. This allows easy
substitution, testing, and extension.
Benefits of Applying DIP
- Promotes loose
coupling
- Improves testability using
mocks/fakes
- Enables flexibility
and scalability
- Encourages interface-driven
design
This
principle is the backbone of dependency injection in
frameworks like ASP.NET Core, where services are registered and
resolved by abstractions — not directly constructed.
DIP
helps build software systems that are modular, reusable, and easy to
refactor as requirements evolve.
Comments
Post a Comment