I am implementing a discount calculation model. One item PER order. I do have a Product class:
public class Product
{
public string Name { get; set; }
public Size Size { get; set; }
public decimal Price { get; set; }
}
I do have an Order class as well:
public class Order
{
public DateTime Date { get; set; }
public string ProductName { get; set; }
public Size Size { get; set; }
}
I have a few discounts:
- Competitive discount - chooses lowest price amongst all products by size. For example, if Latte S size is 2$ and Expresso S size is 3$ then Expresso S size will cost You 2$, 1$ discount will be applied.
- Quantity discount - for x amount one is free in the time period. For example, I buy 2x Latte and 3rd is free and this discount can only be applied daily.
During my implementation, I wanted to use Strategy pattern but I have few nuances:
- A Competitive discount is not dependant on the time period, but Quantity discount is.
- Quantity discount is dependent on the quantity selected, competitive is not (however I could provide value as 1 in implementation, so it would be applied for every item).
Solution:
IDiscount.cs
public interface IDiscount
{
public bool IsApplicable(Order order, int itemsCountForDiscount);
public decimal GetDiscountAmount(Order order);
}
CompetitiveDiscount.cs
public class CompetiveDiscount : IDiscount
{
Size Size { get; set; }
decimal LowestProductPrice { get; set; }
public CompetiveDiscount(Size size)
{
Size = size;
LowestProductPrice = GetLowestProductPriceBySize(size);
}
public decimal GetDiscountAmount(Product product)
{
return product.Price - LowestPriceProvider;
}
public bool IsApplicable(Product product, int itemsCountForDiscount)
{
//returns if applicable
}
private decimal GetLowestProductPriceBySize(Size size)
{
//returns lowest price of products
}
}
QuantityDiscount.cs
public class QuantityDiscount: IDiscount
{
string ProductName { get; set; }
int ItemsCountForDiscount { get; set; }
Period Period { get; set; } //enum for period
public QuantityDiscount(string productName, int itemsCountForDiscount, Period period)
{
ProductName = productName;
ItemsCountForDiscount = itemsCountForDiscount;
Period = period;
}
public decimal GetDiscountAmount(Product product)
{
return product.Price;
}
public bool IsApplicable(Product product, int itemsCountForDiscount)
{
//returns if applicable
}
}
My question would be how could I make this model work if I do need Date in one of the discount, but in another I don't. Is it better to use a Chain of Responsibility design pattern?