Dependency Injection And Inversion Of Control C# - Par Two (Implementation)

Before going through this post, I suggest you go through my previous post for learning the basic concepts of Dependency Injection and Inversion of Control.

Demo on product

This demo is based on a traditional implementation approach. We have a Product class and it has a method which takes the discount and based on some business logic, it applies the discount to the product. The ProductService will interact with the database using ProductRepository. If you notice, the ProductService has a dependency on 2 concrete classes, i.e., Discount and ProductRepository.

  1. new Discount();  
  2. new ProductRepository(); 

We can hence say that ProductService is tightly coupled because of these 2 dependencies.

We may require using different discounts based on several factors such as Product type, some festival, or any other factor. Based on different discounts, we may need to change ProductService class also. In future, you may change the database from SQL to Oracle. Again, it may require ProductService changes, which is the violation of SOLID principles. Just go through the implementation below. I will solve the issues discussed here, in the below section.

  1. using System;  
  2. using System.Collections.Generic;  
  3. namespace DependencyInjection {  
  4.     class Program {}  
  5.     /// <summary>  
  6.     /// Product class  
  7.     /// </summary>  
  8.     public class Product {  
  9.         string Title;  
  10.         string SmallImage;  
  11.         double Price;  
  12.         public void PriceAdjustment(Discount discount) {  
  13.             //Some Business Logic on Products Price based on discount  
  14.         }  
  15.     }  
  16.     /// <summary>  
  17.     /// Disscount class - For Demo you can keep this class Empty as well.  
  18.     /// </summary>  
  19.     public class Discount {  
  20.         /// <summary>  
  21.         /// CampaignId  
  22.         /// </summary>  
  23.         public string CampaignId {  
  24.             get;  
  25.             set;  
  26.         }  
  27.         /// <summary>  
  28.         /// Description  
  29.         /// </summary>  
  30.         public string Description {  
  31.             get;  
  32.             set;  
  33.         }  
  34.         /// <summary>  
  35.         /// DiscountAmount  
  36.         /// </summary>  
  37.         public virtual decimal DiscountAmount {  
  38.             get;  
  39.             set;  
  40.         }  
  41.         /// <summary>  
  42.         /// ExpirationDate  
  43.         /// </summary>  
  44.         public virtual DateTime ExpirationDate {  
  45.             get;  
  46.             set;  
  47.         }  
  48.         /// <summary>  
  49.         /// AdjustmentType  
  50.         /// </summary>  
  51.         public string AdjustmentType {  
  52.             get;  
  53.             set;  
  54.         }  
  55.         /// <summary>  
  56.         /// AdjustmentSubType  
  57.         /// </summary>  
  58.         public string AdjustmentSubType {  
  59.             get;  
  60.             set;  
  61.         }  
  62.         /// <summary>  
  63.         /// CouponCode  
  64.         /// </summary>  
  65.         public string CouponCode {  
  66.             get;  
  67.             set;  
  68.         }  
  69.     }  
  70.     public class ProductRepository {  
  71.         public IEnumerable < Product > GetAllProducts() {  
  72.             return new List < Product > ();  
  73.         }  
  74.     }  
  75.     public class ProductService {  
  76.         private Discount _discount;  
  77.         private ProductRepository _productRepository;  
  78.         public ProductService() {  
  79.             //Dependencies  
  80.             _discount = new Discount();  
  81.             _productRepository = new ProductRepository();  
  82.         }  
  83.         public IEnumerable < Product > GetProducts() {  
  84.             IEnumerable < Product > allProducts = _productRepository.GetAllProducts();  
  85.             foreach(Product p in allProducts) {  
  86.                 p.PriceAdjustment(_discount);  
  87.             }  
  88.             return allProducts;  
  89.         }  
  90.     }  
  91. }  

Solution to the above discussed issues : DI (introduce abstraction)

Create an interface for Discount (IDiscount), and an interface for Repository (IProductRepository).

  1. /// <summary>  
  2. /// IDisscount - For Demo you can keep this class Empty as well.  
  3. /// </summary>  
  4. public interface IDiscount {  
  5.     /// <summary>  
  6.     /// CampaignId  
  7.     /// </summary>  
  8.     string CampaignId {  
  9.         get;  
  10.         set;  
  11.     }  
  12.     /// <summary>  
  13.     /// Description  
  14.     /// </summary>  
  15.     string Description {  
  16.         get;  
  17.         set;  
  18.     }  
  19.     /// <summary>  
  20.     /// DiscountAmount  
  21.     /// </summary>  
  22.     decimal DiscountAmount {  
  23.         get;  
  24.         set;  
  25.     }  
  26.     /// <summary>  
  27.     /// ExpirationDate  
  28.     /// </summary>  
  29.     DateTime ExpirationDate {  
  30.         get;  
  31.         set;  
  32.     }  
  33.     /// <summary>  
  34.     /// AdjustmentType  
  35.     /// </summary>  
  36.     string AdjustmentType {  
  37.         get;  
  38.         set;  
  39.     }  
  40.     /// <summary>  
  41.     /// AdjustmentSubType  
  42.     /// </summary>  
  43.     string AdjustmentSubType {  
  44.         get;  
  45.         set;  
  46.     }  
  47.     /// <summary>  
  48.     /// CouponCode  
  49.     /// </summary>  
  50.     string CouponCode {  
  51.         get;  
  52.         set;  
  53.     }  
  54. }  
  55. public interface IProductRepository {  
  56.     IEnumerable < Product > GetAllProducts();  
  57. }  
  58. public class ProductService {  
  59.     private Discount _discount;  
  60.     // private ProductRepository _productRepository;  
  61.     private IProductRepository _productRepository;  

Modify ProductService accordingly.

  1. public class ProductService {  
  2.     // private Discount _discount;  
  3.     private IDiscount _discount;  
  4.     // private ProductRepository _productRepository;  
  5.     private IProductRepository _productRepository;  
  6.     public ProductService(IProductRepository productRepository) {  
  7.         //Dependencies  
  8.         _discount = new Discount();  
  9.         // _productRepository = new ProductRepository();  
  10.         _productRepository = productRepository;  
  11.     }  
  12.     public IEnumerable < Product > GetProducts() {  
  13.         IEnumerable < Product > allProducts = _productRepository.GetAllProducts();  
  14.         foreach(Product p in allProducts) {  
  15.             p.PriceAdjustment(_discount);  
  16.         }  
  17.         return allProducts;  
  18.     }  
  19. }  

Notice that, after the above changes, PriceAdjustment will break; hence we would modify this also accordingly. Now, PriceAdjustment can work with any kind of Discount that implements IDiscount.

  1. public class Product {  
  2.     string Title;  
  3.     string SmallImage;  
  4.     double Price;  
  5.     public void PriceAdjustment(IDiscount discount) {  
  6.         //Some Business Logic on Products Price based on discount  
  7.     }  
  8. }  

We have injected dependency through the constructor.

Discount dependency is still making the ProductService tightly coupled. Let's refine the ProductService class.

  1. public class ProductService {  
  2.     // private Discount _discount;  
  3.     private IDiscount _discount;  
  4.     // private ProductRepository _productRepository;  
  5.     private IProductRepository _productRepository;  
  6.     public ProductService(IProductRepository productRepository) {  
  7.         //Dependencies  
  8.         // _discount = new Discount();  
  9.         // _productRepository = new ProductRepository();  
  10.         _productRepository = productRepository;  
  11.     }  
  12.     //Injecting Discount dependency  
  13.     public IEnumerable < Product > GetProducts(IDiscount discount) {  
  14.         IEnumerable < Product > allProducts = _productRepository.GetAllProducts();  
  15.         foreach(Product p in allProducts) {  
  16.             p.PriceAdjustment(discount);  
  17.         }  
  18.         return allProducts;  
  19.     }  
  20. }  

To be continued......

Next Recommended Reading Factory Design Pattern In C#