Dependency Inversion Principle
The ‘D’ in SOLID design principles is for the Dependency Inversion Principle. The gist of it is about decoupling the dependency of high-level modules from low-level modules. So that any changes in low-level modules don’t affect the high-level modules.
When I first started coding my high-level modules (user interfaces) would heavily depend on the low-level modules (databases). If I ever wanted to switch to a different database provider it would involve moving the database, as-is, to the new infrastructure, due to these dependencies. Making changes to the database structure would also reflect those changes in code.
To decouple we use interfaces and abstract classes that define the contract for a service or component and then, using dependency injection, we provide the appropriate implementation at runtime.
Again, in keeping with our zoo management system, here’s an example:
// Abstractions (interfaces)
public interface IAnimal
{
void Feed();
}
public interface IZooManagement
{
void FeedAnimals();
}
// Concrete implementations
public class Lion : IAnimals
{
public void Feed()
{
Console.WriteLine("Lion is eating meat.");
}
}
public class Elephant : IAnimals
{
public void Feed()
{
Console.WriteLine("Elephant is eating vegetables.");
}
}
public class ZooManagement : IZooManagement
{
private readonly List<IAnimals> _animals;
public ZooManagement(List<IAnimals> animals)
{
_animals = animals;
}
public void FeedAnimals()
{
foreach (var animal in _animals)
{
animal.Feed();
}
}
}
// Client code
class Program
{
static void Main(string[] args)
{
var animals = new List<IAnimals>
{
new Lion(),
new Elephant()
};
var zooManagement = new ZooManagement(animals);
zooManagement.FeedAnimals();
}
}
In this example, the IZooManagement
interface defines a contract for feeding animals in the zoo, but it does not specify how that should be done. Instead, the ZooManagement
class depends on a list of IAnimals
interfaces, which are implemented by concrete classes such as Lion
and Elephant
.
This creates a loosely coupled relationship and allows us to change the implementation without having to change the contract.