using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
namespace fl.shopper.example
private static void Main(string[] args)
var services = ConfigureServices();
Shopper app = services.GetRequiredService<Shopper>();
private static ServiceProvider ConfigureServices()
var serviceProvider = new ServiceCollection()
.AddTransient<IShoppingCart, SimpleShoppingCart>()
public class Shopper(IShoppingCart cart)
public IShoppingCart Cart = cart;
Cart.AddItem(new CartItem ("SHIRT-01", "Red Shirt", 14.99, 1));
Cart.AddItem(new CartItem ("SHIRT-02", "Blue Shirt", 8.49,3));
Cart.AddItem(new CartItem ("SHIRT-03", "Green Shirt", 17.99, 7));
Cart.AddItem(new CartItem ("BELT", "Brown Belt", 22.49, 1));
Cart.AddItem(new CartItem ("PANTS", "Pants", 14.99, 2));
public interface ICartConfiguration{
public interface IShoppingCart{
void AddItem(ICartItem item);
void AddCoupon(ICoupon coupon);
IReadOnlyList<ICartItem> Items{get;}
ICartConfiguration Config{get;}
public class SimpleShoppingCart: IShoppingCart{
private List<ICartItem> cart_items = new();
private List<ICoupon> coupons = new();
public ICartConfiguration Config => default(ICartConfiguration);
public void AddItem(ICartItem item) => cart_items.Add(item);
public void AddCoupon(ICoupon coupon) => coupons.Add(coupon);
public IReadOnlyList<ICartItem> Items => cart_items.AsReadOnly();
public double SubTotal() => cart_items.Where(x => x is CartItem).Sum(item => item.Cost * item.Qty);
public double Tax() => 0;
public double Discounts() => cart_items.Where(x => x is DiscountCartItem).Sum(item => item.Cost * item.Qty);
public double Total() => SubTotal() + Tax() + Discounts();
private void recalculate_discounts(){
cart_items.RemoveAll(x => x is DiscountCartItem);
foreach(var c in coupons.OrderBy(x => x.AppliesTo)){
public interface ICartItem{
public record class CartItem(string Sku, string Description, double Cost, int Qty) : ICartItem {
public int Qty {get;set;} = Qty;
public record class DiscountCartItem(string Sku, string Description, double Cost, int Qty) : ICartItem {
public int Qty {get;set;} = Qty;
public interface ICoupon{
CouponType AppliesTo {get;}
void Apply(IShoppingCart cart);
public class Save15PercentOffEntirePurchase : ICoupon{
public CouponType AppliesTo => CouponType.AllItems;
public void Apply(IShoppingCart cart){
var discountAmount = cart.SubTotal() * 0.15;
var discountItem = new DiscountCartItem("15%OFF", "Save 15% Off Entire Purchase!", -discountAmount, 1);
cart.AddItem(discountItem);
public class BuyOneShirtGetOneFreeCoupon : ICoupon{
public CouponType AppliesTo => CouponType.EachItem;
public void Apply(IShoppingCart cart){
public static class CartExtensions{
public static void PrintToScreen(this IShoppingCart cart){
var __ = new string ('-',width);
Console.WriteLine($"\nš [{cart.GetType().Name}]\n");
Console.WriteLine($"{"#",2} {"SKU",-16} {"Description",-48} {"Qty",-6} {"Cost",8}");
foreach(var item in cart.Items.Where(x => x is CartItem))
Console.WriteLine($"{index++,2}. {item.Sku,-16} {item.Description,-48} {item.Qty,-5} {item.Cost,8:$0.00}");
var st = $"{"Sub-Total",35}:{cart.SubTotal(),12:$0.00}";
Console.WriteLine($"{st,width-2}");
var discounts = cart.Items.Where(x => x is DiscountCartItem);
Console.WriteLine($"\n{"",2} {"Discounts:",-16}");
foreach(var item in discounts)
Console.WriteLine($"{"$",2} {item.Sku,-16} {item.Description,-48} {item.Qty,-5} {item.Cost,8:$0.00}");
$"{"Discounts",35}:{cart.Discounts(),12:$0.00}",
$"{"Tax " + $"({cart.Config?.TaxRate ?? 0:0.00%})",35}:{cart.Tax(),12:$0.00}",
$"{"Total",35}:{cart.Total(),12:$0.00}"];
foreach(var line in summary)
Console.WriteLine($"{line,width-2}");