public interface ITeaType
public interface ITeaVolume
public class BlackTeaType : ITeaType
public class Less500 : ITeaVolume
public class CustomVolume : ITeaVolume
public int Volume { get; private set; }
public CustomVolume(int Volume)
public interface ITea<out TTeaType, out TTeaVolume>
where TTeaType : ITeaType
where TTeaVolume : ITeaVolume
TTeaType TeaType { get; }
TTeaVolume TeaVolume { get; }
public class Tea<TTeaType, TTeaVolume> : ITea<TTeaType, TTeaVolume>
where TTeaType : ITeaType
where TTeaVolume : ITeaVolume
public Tea(TTeaType teaType, TTeaVolume teaVolume)
this.TeaVolume = teaVolume;
public TTeaType TeaType { get; private set; }
public TTeaVolume TeaVolume { get; private set; }
public class Cake : ICake
public class Coffee : ICoffee
public interface IOrderStuff
public class OnlyTeaStuff<TTeaType, TTeaVolume> : IOrderStuff
where TTeaType : ITeaType
where TTeaVolume : ITeaVolume
public TTeaType TeaType { get; private set; }
public TTeaVolume TeaVolume { get; private set; }
public OnlyTeaStuff(TTeaType teaType, TTeaVolume teaVolume)
this.TeaVolume = teaVolume;
public class CoffeCakeSuff<TCoffee, TCake> : IOrderStuff
public TCoffee Coffee { get; private set; }
public TCake Cake { get; private set; }
public CoffeCakeSuff(TCoffee coffee, TCake cake)
public class TeaCakeSuff<TTea, TCake> : IOrderStuff
where TTea : ITea<BlackTeaType, ITeaVolume>
public ITea<BlackTeaType, ITeaVolume> Tea { get; private set; }
public TCake Cake { get; private set; }
public TeaCakeSuff(TTea tea, TCake cake)
public interface IOrder<out TOrderStuff>
where TOrderStuff : IOrderStuff
TOrderStuff Stuff { get; }
public class OnlyBlackTeaOrder<TTeaVolume> : IOrder<OnlyTeaStuff<BlackTeaType, TTeaVolume>>
where TTeaVolume : ITeaVolume
public OnlyBlackTeaOrder(OnlyTeaStuff<BlackTeaType, TTeaVolume> teaStuff)
public OnlyTeaStuff<BlackTeaType, TTeaVolume> Stuff { get; private set; }
public class CoffeeCakeOrder : IOrder<CoffeCakeSuff<Coffee, Cake>>
public CoffeeCakeOrder(CoffeCakeSuff<Coffee, Cake> stuff)
public CoffeCakeSuff<Coffee, Cake> Stuff { get; private set; }
public class TeaCakeOrder : IOrder<TeaCakeSuff<ITea<BlackTeaType, ITeaVolume>, Cake>>
public TeaCakeOrder(TeaCakeSuff<ITea<BlackTeaType, ITeaVolume>, Cake> stuff)
public TeaCakeSuff<ITea<BlackTeaType, ITeaVolume>, Cake> Stuff { get; private set; }
public interface IOrderPrintProcessor<in TOrderStuff>
where TOrderStuff : IOrderStuff
void ProcessAlgorithm(IOrder<TOrderStuff> order);
public class OnlyBlackTeaLess500PrintProcessor : IOrderPrintProcessor<OnlyTeaStuff<BlackTeaType, Less500>>
public void ProcessAlgorithm(IOrder<OnlyTeaStuff<BlackTeaType, Less500>> order)
Console.WriteLine("Execute Only black tea < 500 vol {0}", order.Stuff.TeaType);
public class OnlyBlackTeaCustomPrintProcessor : IOrderPrintProcessor<OnlyTeaStuff<BlackTeaType, CustomVolume>>
public void ProcessAlgorithm(IOrder<OnlyTeaStuff<BlackTeaType, CustomVolume>> order)
Console.WriteLine("Execute Only black custom {0} vol", order.Stuff.TeaVolume.Volume);
public class TeaCakePrintProcessor : IOrderPrintProcessor<TeaCakeSuff<ITea<BlackTeaType, ITeaVolume>, Cake>>
public void ProcessAlgorithm(IOrder<TeaCakeSuff<ITea<BlackTeaType, ITeaVolume>, Cake>> order)
Console.WriteLine("Execute tea {0} and cake {1}", order.Stuff.Tea, order.Stuff.Cake);
public class CoffeeCakePrintProcessor : IOrderPrintProcessor<CoffeCakeSuff<Coffee, Cake>>
public void ProcessAlgorithm(IOrder<CoffeCakeSuff<Coffee, Cake>> order)
Console.WriteLine("Execute coffee {0} and cake {1}", order.Stuff.Coffee, order.Stuff.Cake);
public static class OrderPrintProcessorExecutor
public static void Execute<TOrderProcessor, TOrderStuff>(IOrder<TOrderStuff> order)
where TOrderStuff : IOrderStuff
where TOrderProcessor : IOrderPrintProcessor<TOrderStuff>, new()
new TOrderProcessor().ProcessAlgorithm(order);
public static void Main()
var order1 = new OnlyBlackTeaOrder<CustomVolume>
(new OnlyTeaStuff<BlackTeaType, CustomVolume>(
OrderPrintProcessorExecutor.Execute<OnlyBlackTeaCustomPrintProcessor, OnlyTeaStuff<BlackTeaType, CustomVolume>>(order1);
var order2 = new OnlyBlackTeaOrder<Less500>
(new OnlyTeaStuff<BlackTeaType, Less500>(
OrderPrintProcessorExecutor.Execute<OnlyBlackTeaLess500PrintProcessor, OnlyTeaStuff<BlackTeaType, Less500>>(order2);
var order3 = new CoffeeCakeOrder(new CoffeCakeSuff<Coffee, Cake>(new Coffee(), new Cake()));
OrderPrintProcessorExecutor.Execute<CoffeeCakePrintProcessor, CoffeCakeSuff<Coffee, Cake>>(order3);
var order4 = new TeaCakeOrder(
new TeaCakeSuff<ITea<BlackTeaType, ITeaVolume>, Cake>
(new Tea<BlackTeaType, CustomVolume>(new BlackTeaType(), new CustomVolume(200)), new Cake()));
OrderPrintProcessorExecutor.Execute<TeaCakePrintProcessor, TeaCakeSuff<ITea<BlackTeaType, ITeaVolume>, Cake>>(order4);