public abstract class AbstractCalculator
{
public abstract decimal Calculate(decimal currentTotal, Order order);
}
public class TotalCalculator : AbstractCalculator
private decimal CalculateTotal(Order order)
decimal total = 0;
foreach (OrderItem item in order.Items)
total += (item.Quantity*item.CostPerItem);
return total;
public override decimal Calculate(decimal currentTotal, Order order)
return currentTotal + CalculateTotal(order);
public class GstCalculator : AbstractCalculator
private decimal _gstRate = 1.125m;
public decimal GstRate
get { return _gstRate; }
set { _gstRate = value; }
private bool IsNewZealand(Order order)
return (order.CountryCode == "NZ");
if (IsNewZealand(order))
return (currentTotal*_gstRate);
return currentTotal;
public class ShippingCalculator : AbstractCalculator
private decimal _shippingCost = 5.0m;
private decimal _fragileShippingPremium = 1.5m;
public decimal ShippingCost
get { return _shippingCost; }
set { _shippingCost = value; }
public decimal FragileShippingPremium
get { return _fragileShippingPremium; }
set { _fragileShippingPremium = value; }
private decimal GetShippingTotal(Order order)
decimal shippingTotal = 0;
decimal itemShippingCost = ShippingCost*item.Quantity;
if (item.IsFragile) itemShippingCost *= FragileShippingPremium;
shippingTotal += itemShippingCost;
return shippingTotal;
return currentTotal + GetShippingTotal(order);
public class DefaultCostCalculator : ICostCalculator
private AbstractCalculator[] _calculators;
public DefaultCostCalculator(AbstractCalculator[] calculators)
_calculators = calculators;
public decimal CalculateTotal(Order order)
decimal currentTotal = 0;
foreach (AbstractCalculator calculator in _calculators)
currentTotal = calculator.Calculate(currentTotal, order);
<configuration>
<configSections>
<section name="castle"
type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
</configSections>
<castle>
<components>
<component id="calc.gst"
service="IoC.Tutorials.Part13.AbstractCalculator, IoC.Tutorials.Part13"
type="IoC.Tutorials.Part13.GstCalculator, IoC.Tutorials.Part13">
<parameters>
<GstRate>1.20</GstRate>
<!-- GST is now 20% -->
</parameters>
</component>
<component id="calc.shipping"
type="IoC.Tutorials.Part13.ShippingCalculator, IoC.Tutorials.Part13">
<FragileShippingPremium>0.0</FragileShippingPremium>
<!-- No fragile goods premium any more-->
<component id="calc.total"
type="IoC.Tutorials.Part13.TotalCalculator, IoC.Tutorials.Part13" />
<component id="costCalculator.default"
service="IoC.Tutorials.Part13.ICostCalculator, IoC.Tutorials.Part13"
type="IoC.Tutorials.Part13.DefaultCostCalculator, IoC.Tutorials.Part13">
<calculators>
<array>
<value>${calc.total}</value>
<value>${calc.shipping}</value>
<value>${calc.gst}</value>
</array>
</calculators>
</components>
</castle>
</configuration>
private static void Main(string[] args)
WindsorContainer container = new WindsorContainer(new XmlInterpreter());
Order order1 = new Order();
order1.CountryCode = "NZ";
order1.Items.Add(new OrderItem("water", 10, 1.0m, false));
order1.Items.Add(new OrderItem("glass", 5, 20.0m, true));
Order order2 = new Order();
order2.CountryCode = "US";
order2.Items.Add(new OrderItem("sand", 50, 0.2m, false));
ICostCalculator costCalculator = container.Resolve<ICostCalculator>();
Console.WriteLine("Cost to deliver Order 1: {0}", costCalculator.CalculateTotal(order1));
Console.WriteLine("Cost to deliver Order 2: {0}", costCalculator.CalculateTotal(order2));
Console.Read();