Before going through this post, I suggest you to go through my previous post on basic concepts in 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 on the product. Product service will interact with database using ProductRepository. If you will notice ProductService has dependency on 2 concrete classes i.e. Discount and ProductRepository
new Discount();
new ProductRepository();
We can hence say that ProductService is tightly coupled because of these 2 dependencies.
We may require to use different discount 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 violating the SOLID principles. Just go through the implementation below, I will solution the issues discussed here in below section.
using System;
using System.Collections.Generic;
namespace DependencyInjection
{
class Program
{
}
/// <summary>
/// Product class
/// </summary>
public class Product
{
string Title;
string SmallImage;
double Price;
public void PriceAdjustment(Discount discount)
{
//Some Business Logic on Products Price based on discount
}
}
/// <summary>
/// Disscount class - For Demo you can keep this class Empty as well.
/// </summary>
public class Discount
{
/// <summary>
/// CampaignId
/// </summary>
public string CampaignId { get; set; }
/// <summary>
/// Description
/// </summary>
public string Description { get; set; }
/// <summary>
/// DiscountAmount
/// </summary>
public virtual decimal DiscountAmount { get; set; }
/// <summary>
/// ExpirationDate
/// </summary>
public virtual DateTime ExpirationDate { get; set; }
/// <summary>
/// AdjustmentType
/// </summary>
public string AdjustmentType { get; set; }
/// <summary>
/// AdjustmentSubType
/// </summary>
public string AdjustmentSubType { get; set; }
/// <summary>
/// CouponCode
/// </summary>
public string CouponCode { get; set; }
}
public class ProductRepository
{
public IEnumerable<Product> GetAllProducts()
{
return new List<Product>();
}
}
public class ProductService
{
private Discount _discount;
private ProductRepository _productRepository;
public ProductService()
{
//Dependencies
_discount = new Discount();
_productRepository = new ProductRepository();
}
public IEnumerable<Product> GetProducts()
{
IEnumerable<Product> allProducts = _productRepository.GetAllProducts();
foreach (Product p in allProducts)
{
p.PriceAdjustment(_discount);
}
return allProducts;
}
}
}
Solution to above discussed issues : DI (introduce abstraction)
Create Interface for Discount (IDiscount) , Interface for Repository (IProductRepository).
/// <summary>
/// IDisscount - For Demo you can keep this class Empty as well.
/// </summary>
public interface IDiscount {
/// <summary>
/// CampaignId
/// </summary>
string CampaignId { get; set; }
/// <summary>
/// Description
/// </summary>
string Description { get; set; }
/// <summary>
/// DiscountAmount
/// </summary>
decimal DiscountAmount { get; set; }
/// <summary>
/// ExpirationDate
/// </summary>
DateTime ExpirationDate { get; set; }
/// <summary>
/// AdjustmentType
/// </summary>
string AdjustmentType { get; set; }
/// <summary>
/// AdjustmentSubType
/// </summary>
string AdjustmentSubType { get; set; }
/// <summary>
/// CouponCode
/// </summary>
string CouponCode { get; set; }
}
public interface IProductRepository
{
IEnumerable<Product> GetAllProducts();
}
public class ProductService
{
private Discount _discount;
// private ProductRepository _productRepository;
private IProductRepository _productRepository;
Modify ProductService accordingly.
public class ProductService
{
// private Discount _discount;
private IDiscount _discount;
// private ProductRepository _productRepository;
private IProductRepository _productRepository;
public ProductService(IProductRepository productRepository)
{
//Dependencies
_discount = new Discount();
// _productRepository = new ProductRepository();
_productRepository = productRepository;
}
public IEnumerable<Product> GetProducts()
{
IEnumerable<Product> allProducts = _productRepository.GetAllProducts();
foreach (Product p in allProducts)
{
p.PriceAdjustment(_discount);
}
return allProducts;
}
}
To be continued......
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 on the product. Product service will interact with database using ProductRepository. If you will notice ProductService has dependency on 2 concrete classes i.e. Discount and ProductRepository
new Discount();
new ProductRepository();
We can hence say that ProductService is tightly coupled because of these 2 dependencies.
We may require to use different discount 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 violating the SOLID principles. Just go through the implementation below, I will solution the issues discussed here in below section.
using System;
using System.Collections.Generic;
namespace DependencyInjection
{
class Program
{
}
/// <summary>
/// Product class
/// </summary>
public class Product
{
string Title;
string SmallImage;
double Price;
public void PriceAdjustment(Discount discount)
{
//Some Business Logic on Products Price based on discount
}
}
/// <summary>
/// Disscount class - For Demo you can keep this class Empty as well.
/// </summary>
public class Discount
{
/// <summary>
/// CampaignId
/// </summary>
public string CampaignId { get; set; }
/// <summary>
/// Description
/// </summary>
public string Description { get; set; }
/// <summary>
/// DiscountAmount
/// </summary>
public virtual decimal DiscountAmount { get; set; }
/// <summary>
/// ExpirationDate
/// </summary>
public virtual DateTime ExpirationDate { get; set; }
/// <summary>
/// AdjustmentType
/// </summary>
public string AdjustmentType { get; set; }
/// <summary>
/// AdjustmentSubType
/// </summary>
public string AdjustmentSubType { get; set; }
/// <summary>
/// CouponCode
/// </summary>
public string CouponCode { get; set; }
}
public class ProductRepository
{
public IEnumerable<Product> GetAllProducts()
{
return new List<Product>();
}
}
public class ProductService
{
private Discount _discount;
private ProductRepository _productRepository;
public ProductService()
{
//Dependencies
_discount = new Discount();
_productRepository = new ProductRepository();
}
public IEnumerable<Product> GetProducts()
{
IEnumerable<Product> allProducts = _productRepository.GetAllProducts();
foreach (Product p in allProducts)
{
p.PriceAdjustment(_discount);
}
return allProducts;
}
}
}
Solution to above discussed issues : DI (introduce abstraction)
Create Interface for Discount (IDiscount) , Interface for Repository (IProductRepository).
/// <summary>
/// IDisscount - For Demo you can keep this class Empty as well.
/// </summary>
public interface IDiscount {
/// <summary>
/// CampaignId
/// </summary>
string CampaignId { get; set; }
/// <summary>
/// Description
/// </summary>
string Description { get; set; }
/// <summary>
/// DiscountAmount
/// </summary>
decimal DiscountAmount { get; set; }
/// <summary>
/// ExpirationDate
/// </summary>
DateTime ExpirationDate { get; set; }
/// <summary>
/// AdjustmentType
/// </summary>
string AdjustmentType { get; set; }
/// <summary>
/// AdjustmentSubType
/// </summary>
string AdjustmentSubType { get; set; }
/// <summary>
/// CouponCode
/// </summary>
string CouponCode { get; set; }
}
public interface IProductRepository
{
IEnumerable<Product> GetAllProducts();
}
public class ProductService
{
private Discount _discount;
// private ProductRepository _productRepository;
private IProductRepository _productRepository;
Modify ProductService accordingly.
public class ProductService
{
// private Discount _discount;
private IDiscount _discount;
// private ProductRepository _productRepository;
private IProductRepository _productRepository;
public ProductService(IProductRepository productRepository)
{
//Dependencies
_discount = new Discount();
// _productRepository = new ProductRepository();
_productRepository = productRepository;
}
public IEnumerable<Product> GetProducts()
{
IEnumerable<Product> allProducts = _productRepository.GetAllProducts();
foreach (Product p in allProducts)
{
p.PriceAdjustment(_discount);
}
return allProducts;
}
}
Notice that, after above change PriceAdjustment will break hence we would modify this also accordingly. Now PriceAdjustment can work with any kind of Discount that implements IDiscount.
public class Product
{
string Title;
string SmallImage;
double Price;
public void PriceAdjustment(IDiscount discount)
{
//Some Business Logic on Products Price based on discount
}
}
We have injected dependency through constructor.
Discount dependency is still making the ProductService tightly coupled. Let's refine the ProductService class.
public class ProductService
{
// private Discount _discount;
private IDiscount _discount;
// private ProductRepository _productRepository;
private IProductRepository _productRepository;
public ProductService(IProductRepository productRepository)
{
//Dependencies
// _discount = new Discount();
// _productRepository = new ProductRepository();
_productRepository = productRepository;
}
//Injecting Discount dependency
public IEnumerable<Product> GetProducts(IDiscount discount)
{
IEnumerable<Product> allProducts = _productRepository.GetAllProducts();
foreach (Product p in allProducts)
{
p.PriceAdjustment(discount);
}
return allProducts;
}
}
To be continued......
Comments
Post a Comment