The Dependency Inversion Principle (DIP) states that:
High-level modules should not depend on low-level modules.
Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions.
In other words, this principle encourages the use of abstractions to decouple high-level and low-level modules, making the code more modular and easier to maintain, test, and extend.
Violation of the principle
Imagine having an application for logging messages, where a high-level Logger
class is directly dependent on a low-level FileLogger
class:
public class FileLogger
{
public void LogMessage(string message)
{
// Write the message to a file
}
}
public class Logger
{
private readonly FileLogger _fileLogger;
public Logger()
{
_fileLogger = new FileLogger();
}
public void Log(string message)
{
_fileLogger.LogMessage(message);
}
}
In this example, the DIP is violated because the high-level Logger
class is directly dependent on the low-level FileLogger
class. This design can make the code less flexible and harder to maintain, as changes in the FileLogger
class could affect the Logger
class, and it would be difficult to switch to a different logging mechanism.
Application of the principle
To resolve the violation of the DIP, we can introduce an abstraction for logging and use dependency injection to decouple the high-level and low-level modules:
public interface ILogger
{
void LogMessage(string message);
}
public class FileLogger : ILogger
{
public void LogMessage(string message)
{
// Write the message to a file
}
}
public class Logger
{
private readonly ILogger _logger;
public Logger(ILogger logger)
{
_logger = logger;
}
public void Log(string message)
{
_logger.LogMessage(message);
}
}
Now, the high-level Logger
class depends on the ILogger
abstraction instead of the low-level FileLogger
class, and the Dependency Inversion Principle is respected. This decoupling makes the code more modular, easier to maintain, and allows for easy substitution of different logging mechanisms.
Conclusion
In this article, we have summarized the Dependency Inversion Principle, which teaches us to design high-level modules to depend on abstractions, not low-level modules, to decouple high-level and low-level modules using abstractions and dependency injection, and to make the code more maintainable and flexible by minimizing the impact of changes in low-level modules on high-level modules.
Top comments (0)