DEV Community

Fabrizio Bagalà
Fabrizio Bagalà

Posted on • Edited on

Dependency Inversion Principle

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

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.

References

Top comments (0)