I recently came across a problem, and I thought I would try to flex some of my developer muscle to try to solve it. The problem reads as follows:

Basic sales tax is applicable at a rate of 10% on all goods, except books, food, and medical products that are exempt. 
Import duty is an additional sales tax applicable on all imported goods at a rate of 5%, with no exemptions.  
When I purchase items I receive a receipt which lists the name of all the items and their price (including tax), 
finishing with the total cost of the items, and the total amounts of sales taxes paid.
The rounding rules for sales tax are that for a tax rate of n%, a shelf price of p contains (np/100 rounded up to the nearest 0.05) amount of sales tax.  
Write an application that prints out the receipt details for these shopping baskets... INPUT:
Input 1: 1 book at 12.49 1 music CD at 14.99 1 chocolate bar at 0.85  
Input 2: 1 imported box of chocolates at 10.00 1 imported bottle of perfume at 47.50  
Input 3: 1 imported bottle of perfume at 27.99 1 bottle of perfume at 18.99 1 packet of headache pills at 9.75 1 box of imported chocolates at 11.25  
OUTPUT  
Output 1: 1 book : 12.49 1 music CD: 16.49 1 chocolate bar: 0.85 Sales Taxes: 1.50 Total: 29.83  
Output 2: 1 imported box of chocolates: 10.50 1 imported bottle of perfume: 54.65 Sales Taxes: 7.65 Total: 65.15  
Output 3: 1 imported bottle of perfume: 32.19 1 bottle of perfume: 20.89 1 packet of headache pills: 9.75 1 imported box of chocolates: 11.85 Sales Taxes: 6.70 Total: 74.68 ==========

To solve this problem I used a composite to calculate taxes. The “TaxComposite” type allows you to bundle several different taxes all in one type. So when calculating taxes, the calculation with iterate through all the taxes and add the calculated tax and return the total value.

public class TaxComposite : ITax 
  {
      public TaxComposite( params ITax[] taxes ) : this( new List< ITax >( taxes ) ) {}

      public TaxComposite( IEnumerable< ITax > taxes ) 
      {
          _taxes = new List< ITax >( taxes );
          _amount = CalculateAmount( );
          _type = CalculateType( );
      }

      public double Amount 
      {
          get { return _amount; }
      }

      public TaxTypes Type 
      {
          get { return _type; }
      }

      public IMoney CalculateTaxFor( IMoney price ) 
      {
          return CalculateTaxFor( price, RoundingDelegateFactory.RoundToNearestTenCents );
      }

      public IMoney CalculateTaxFor( IMoney price, RoundingStrategy round ) 
      {
          IMoney total = new Money( );
          Summary( delegate( ITax tax ) { total = total.Add( tax.CalculateTaxFor( price, round ) ); } );
          return total;
      }

      private double CalculateAmount( ) 
      {
          double amount = 0d;
          Summary( delegate( ITax tax ) { amount += tax.Amount; } );
          return amount;
      }

      private TaxTypes CalculateType( ) 
      {
          TaxTypes type = TaxTypes.None;
          Summary( delegate( ITax tax ) { type = type | tax.Type; } );
          return type;
      }

      private void Summary( Action< ITax > toDo ) 
      {
          foreach ( ITax tax in _taxes ) {
              toDo( tax );
          }
      }

      private readonly IList< ITax > _taxes;
      private readonly double _amount;
      private readonly TaxTypes _type;
  }
"The Composite Pattern allows you to compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly." - Head First Design Patterns

I used a TaxFactory type to construct the TaxComposite type which gathers all the taxes that match a specified predicate and injects it into the TaxComposite constructor. It looks like…

public static class TaxFactory 
{
  public static ITax Create( TaxTypes forTaxes ) 
  {
      return new TaxComposite( Taxes.FindBy( delegate( ITax tax ) { return ( tax.Type & forTaxes ) == tax.Type; } ) );
  }

The tax type is an enum that uses the flags attribute so that I can enable different bits for different taxes.

[Flags]
  public enum TaxTypes 
  {
      None = 0x00,
      Sales = 0x01,
      Import = 0x02
  }

Taxes is a static type that contains different types of taxes. The FindBy method allows for different strategies to be passed into to gather different types of taxes based on different critera. The above example returns all the taxes that are enabled in the “forTaxes” argument. FindBy is defined like…

public static IEnumerable< ITax > FindBy( Predicate< ITax > condition ) 
  {
      foreach ( ITax tax in taxes ) 
      {
          if ( condition( tax ) ) 
          {
              yield return tax;
          }
      }
  }

I’m not sure if this is the most flexible design, but if i need to make changes to tax rates I can do that in one spot. The only catch is that it requires a re-compile to take a effect. In a full blown implementation I may want to consider using a “service” to retrieve the tax rates. Also, in this implementation in order to add new taxes I have to added it too 2 different locations. The first is the TaxTypes enum and the second is the Taxes static holder class. This leaves a bit of a smell…

** Head First Design Patterns (Head First)** by Elisabeth Freeman, Eric Freeman, Bert Bates, Kathy Sierra
Read more about this title…

comments powered by Disqus