Level: Intermediate + to Object Oriented Programming;
Beginner + with .Net and C#
Frequently with applications, many of the operations they
perform are dynamic depending on several factors. Think about a common
scenario, Sales Tax. Tax amounts are based off the place where you live.
There are many different tax rates in each country. A good method of
implementing dynamic patterns like taxes is needed. The strategy pattern
covers this gap for us.
The strategy pattern is very useful when a dynamic formula
or data is needed. In our situation it will allow us to swap out different tax
objects when needed. The pattern lets a class take on many different behaviors
depending on the context in which it is used.
The strategy patterns starts with an interface that defines
the methods that each different behavior defines. Our tax interface is simple,
only one method that returns the (full amount of the price) * (the tax amount).
Listing 14
using System;
namespace StrategyPattern
{
public interface ITaxStrategy
{
double CalculateTax(double amount);
}
}
This interface will be implemented in all of our tax
strategy classes to give them a common base.
Two simple classes are then created for calculating taxes
for the USA and the UK. Both tax rates are made-up, 5% for the USA and 7% for the UK.
Listing 15
using System;
namespace StrategyPattern
{
public class USATax: ITaxStrategy
{
public USATax(){}
public double CalculateTax(double amount)
{
return amount * 1.05;
}
}
}
using System;
namespace StrategyPattern
{
public class UKTax: ITaxStrategy
{
public UKTax(){}
public double CalculateTax(double amount)
{
return amount * 1.07;
}
}
}
To demonstrate the use of the two classes, we will create a
simple inventory item class that represents an item in our stores inventory.
The class will hold the price of the item.
Listing 16
using System;
namespace StrategyPattern
{
public class InventoryItem
{
private ITaxStrategy _ItemTax;
private double _ItemAmount;
public InventoryItem(){}
public void SetTax(ITaxStrategy tax)
{
_ItemTax = tax;
}
public double ItemAmount
{
get
{
return _ItemAmount;
}
set
{
_ItemAmount = value;
}
}
public double ItemWithTax
{
get
{
return_ItemTax.CalculateTax(_ItemAmount);
}
}
}
}
Now let us examine the code that makes the class use the
strategy pattern. A private variable named _ItemTax is declared as type
ITaxStrategy. This is our internal representation of which strategy we want
the class to use. The SetTax method allows us to set whichever strategy object
we need to the inventory item. The property ItemWithTax returns the item’s
amount with the tax added into it by calling the CalculateTax method on our
strategy object.
To see the classes in motion the following code can be used.
Listing 17
InventoryItem itm;
itm = new InventoryItem();
itm.ItemAmmount = (double)10;
USATax usaTax;
usaTax = new USATax();
UKTax ukTax;
ukTax = new UKTax();
itm.SetTax(usaTax);
MessageBox.Show(itm.ItemWithTax.ToString());
itm.SetTax(ukTax);
MessageBox.Show(itm.ItemWithTax.ToString());
The first thing we do is create an object of the
InventoryItem class. We then create a US tax object and a UK tax object. After setting the tax object to our inventory class, the message boxes show the
result. You will get 10.5 for the first tax and 10.7 for the second, showing
the different strategies in action.
While this is just a demonstration, in a real world
application the tax objects would be created dynamically based on a registry
key, configuration file, or based on the findings of a reflection call. One
technique I have used is to use reflection to query the install directory for a
class that implements the ITaxStrategy interface. When the product is
installed, the user chooses what region they are in and the correct dll with
the tax class is installed. Reflection can then find this class and create an
instance of it on the fly to pass to the inventory class.