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.).
Code:
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.
Code:
using System;
namespace StrategyPattern
{
public class USATax : ITaxStrategy
{
public USATax()
{
}
public double CalculateTax(double amount)
{
return amount * 1.05;
}
}
}
Code:
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 just hold the price of the item.
Code:
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 lets examine the code that makes the class use the strategy pattern. A private variable names _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 this code can be used.
Code:
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, database, 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.