Consider a data access scenario where a service class needs to interact with a data repository.
public class ProductRepository
{
public void Add(Product product)
{
// Code to add product to database
}
public Product Get(int id)
{
// Code to get product from database
return new Product();
}
}
public class ProductService
{
private ProductRepository _productRepository;
public ProductService()
{
_productRepository = new ProductRepository();
}
public void AddProduct(Product product)
{
_productRepository.Add(product);
}
public Product GetProduct(int id)
{
return _productRepository.Get(id);
}
}
In this example, the ProductService class directly depends on the ProductRepository class, violating DIP.
Introduce an abstraction for the repository.
public interface IProductRepository
{
void Add(Product product);
Product Get(int id);
}
public class ProductRepository : IProductRepository
{
public void Add(Product product)
{
// Code to add product to database
}
public Product Get(int id)
{
// Code to get product from database
return new Product();
}
}
public class ProductService
{
private readonly IProductRepository _productRepository;
public ProductService(IProductRepository productRepository)
{
_productRepository = productRepository;
}
public void AddProduct(Product product)
{
_productRepository.Add(product);
}
public Product GetProduct(int id)
{
return _productRepository.Get(id);
}
}
In this design, the ProductService class depends on the IProductRepository interface. This makes it easy to swap out the ProductRepository for a different implementation if needed (e.g., a mock repository for testing).