Dependency Inversion Principle (DIP) is an architectural principle that states:
This means that business logic (for example, the order handling service) should not know and directly use specific implementations of infrastructure (for example, a class that implements email sending) but should work through an abstraction (interface), which you inject via a DI container or manually.
Example code in C#:
public interface IEmailSender { void Send(string to, string message); } public class SmtpEmailSender : IEmailSender { public void Send(string to, string message) { // Implementation of sending email } } public class OrderService { private readonly IEmailSender _emailSender; public OrderService(IEmailSender emailSender) { _emailSender = emailSender; } public void PlaceOrder(string customer) { // business logic _emailSender.Send(customer, "Your order is placed!"); } }
Key features:
Is DIP just dependency injection via constructors?
No. DIP is about separating abstractions from implementations. Dependency Injection (DI) is only a tool through which DIP is realized. DIP can also be implemented without a DI container by manually ensuring the separation of abstractions and details.
If you have one implementation of the interface, is DIP mandatory?
Yes, the principle still applies if extension is possible. Introducing abstractions prepares the system for changes in requirements without modifying high-level code. Even with one implementation of the interface, loose coupling facilitates testing and system development.
Can you violate DIP by using logic in factories or service locators?
Yes. If a factory or service locator knows about implementation details and dynamically binds them without using an interface on the client side, DIP is violated despite the external presence of abstractions.